diff options
Diffstat (limited to 'contrib/wpa/wpa_supplicant')
105 files changed, 17689 insertions, 5764 deletions
diff --git a/contrib/wpa/wpa_supplicant/Android.mk b/contrib/wpa/wpa_supplicant/Android.mk index a8d6a7f944e9..529693131308 100644 --- a/contrib/wpa/wpa_supplicant/Android.mk +++ b/contrib/wpa/wpa_supplicant/Android.mk @@ -92,7 +92,10 @@ OBJS += eap_register.c OBJS += src/utils/common.c OBJS += src/utils/wpa_debug.c OBJS += src/utils/wpabuf.c +OBJS += src/utils/bitfield.c OBJS += wmm_ac.c +OBJS += op_classes.c +OBJS += rrm.c OBJS_p = wpa_passphrase.c OBJS_p += src/utils/common.c OBJS_p += src/utils/wpa_debug.c @@ -204,6 +207,12 @@ L_CFLAGS += -DCONFIG_SUITEB192 NEED_SHA384=y endif +ifdef CONFIG_OCV +L_CFLAGS += -DCONFIG_OCV +OBJS += src/common/ocv.c +CONFIG_IEEE80211W=y +endif + ifdef CONFIG_IEEE80211W L_CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y @@ -221,8 +230,6 @@ ifdef CONFIG_MESH NEED_80211_COMMON=y NEED_SHA256=y NEED_AES_SIV=y -NEED_AES_OMAC1=y -NEED_AES_CTR=y CONFIG_SAE=y CONFIG_AP=y L_CFLAGS += -DCONFIG_MESH @@ -238,6 +245,50 @@ NEED_ECC=y NEED_DH_GROUPS=y endif +ifdef CONFIG_DPP +L_CFLAGS += -DCONFIG_DPP +OBJS += src/common/dpp.c +OBJS += dpp_supplicant.c +NEED_AES_SIV=y +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_JSON=y +NEED_GAS_SERVER=y +NEED_BASE64=y +ifdef CONFIG_DPP2 +L_CFLAGS += -DCONFIG_DPP2 +endif +endif + +ifdef CONFIG_OWE +L_CFLAGS += -DCONFIG_OWE +NEED_ECC=y +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_FILS +L_CFLAGS += -DCONFIG_FILS +NEED_SHA384=y +NEED_AES_SIV=y +ifdef CONFIG_FILS_SK_PFS +L_CFLAGS += -DCONFIG_FILS_SK_PFS +NEED_ECC=y +endif +endif + +ifdef CONFIG_MBO +CONFIG_WNM=y +endif + ifdef CONFIG_WNM L_CFLAGS += -DCONFIG_WNM OBJS += wnm_sta.c @@ -254,15 +305,14 @@ ifdef CONFIG_TDLS_TESTING L_CFLAGS += -DCONFIG_TDLS_TESTING endif -ifdef CONFIG_PEERKEY -L_CFLAGS += -DCONFIG_PEERKEY +ifdef CONFIG_PMKSA_CACHE_EXTERNAL +L_CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL endif ifndef CONFIG_NO_WPA OBJS += src/rsn_supp/wpa.c OBJS += src/rsn_supp/preauth.c OBJS += src/rsn_supp/pmksa_cache.c -OBJS += src/rsn_supp/peerkey.c OBJS += src/rsn_supp/wpa_ie.c OBJS += src/common/wpa_common.c NEED_AES=y @@ -294,7 +344,6 @@ OBJS += src/p2p/p2p_invitation.c OBJS += src/p2p/p2p_dev_disc.c OBJS += src/p2p/p2p_group.c OBJS += src/ap/p2p_hostapd.c -OBJS += src/utils/bitfield.c L_CFLAGS += -DCONFIG_P2P NEED_GAS=y NEED_OFFCHANNEL=y @@ -640,6 +689,7 @@ 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 endif ifdef CONFIG_EAP_EKE @@ -811,13 +861,20 @@ OBJS += src/ap/ieee802_11_ht.c ifdef CONFIG_IEEE80211AC OBJS += src/ap/ieee802_11_vht.c endif +ifdef CONFIG_IEEE80211AX +OBJS += src/ap/ieee802_11_he.c endif -ifdef CONFIG_WNM +endif +ifdef CONFIG_WNM_AP +L_CFLAGS += -DCONFIG_WNM_AP OBJS += src/ap/wnm_ap.c endif ifdef CONFIG_MBO OBJS += src/ap/mbo_ap.c endif +ifdef CONFIG_FILS +OBJS += src/ap/fils_hlp.c +endif ifdef CONFIG_CTRL_IFACE OBJS += src/ap/ctrl_iface_ap.c endif @@ -832,11 +889,9 @@ L_CFLAGS += -DCONFIG_IEEE80211N ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211AX +L_CFLAGS += -DCONFIG_IEEE80211AX endif - -ifdef CONFIG_MBO -OBJS += mbo.c -L_CFLAGS += -DCONFIG_MBO endif ifdef NEED_AP_MLME @@ -852,6 +907,10 @@ L_CFLAGS += -DEAP_SERVER_WSC OBJS += src/ap/wps_hostapd.c OBJS += src/eap_server/eap_server_wsc.c endif +ifdef CONFIG_DPP +OBJS += src/ap/dpp_hostapd.c +OBJS += src/ap/gas_query_ap.c +endif ifdef CONFIG_INTERWORKING OBJS += src/ap/gas_serv.c endif @@ -860,18 +919,21 @@ OBJS += src/ap/hs20.c endif endif +ifdef CONFIG_MBO +OBJS += mbo.c +L_CFLAGS += -DCONFIG_MBO +endif + +ifdef CONFIG_TESTING_OPTIONS +L_CFLAGS += -DCONFIG_TESTING_OPTIONS +endif + ifdef NEED_RSN_AUTHENTICATOR L_CFLAGS += -DCONFIG_NO_RADIUS NEED_AES_WRAP=y OBJS += src/ap/wpa_auth.c OBJS += src/ap/wpa_auth_ie.c OBJS += src/ap/pmksa_cache_auth.c -ifdef CONFIG_IEEE80211R -OBJS += src/ap/wpa_auth_ft.c -endif -ifdef CONFIG_PEERKEY -OBJS += src/ap/peerkey_auth.c -endif endif ifdef CONFIG_ACS @@ -971,25 +1033,40 @@ ifdef CONFIG_TLS_ADD_DL LIBS += -ldl LIBS_p += -ldl endif +ifndef CONFIG_TLS_DEFAULT_CIPHERS +CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" +endif +L_CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" endif ifeq ($(CONFIG_TLS), gnutls) +ifndef CONFIG_CRYPTO +# default to libgcrypt +CONFIG_CRYPTO=gnutls +endif ifdef TLS_FUNCS OBJS += src/crypto/tls_gnutls.c LIBS += -lgnutls -lgpg-error endif -OBJS += src/crypto/crypto_gnutls.c -OBJS_p += src/crypto/crypto_gnutls.c +OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c +OBJS_p += src/crypto/crypto_$(CONFIG_CRYPTO).c ifdef NEED_FIPS186_2_PRF OBJS += src/crypto/fips_prf_internal.c OBJS += src/crypto/sha1-internal.c endif +ifeq ($(CONFIG_CRYPTO), gnutls) LIBS += -lgcrypt LIBS_p += -lgcrypt -CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif +ifeq ($(CONFIG_CRYPTO), nettle) +LIBS += -lnettle -lgmp +LIBS_p += -lnettle -lgmp +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +endif ifeq ($(CONFIG_TLS), internal) ifndef CONFIG_CRYPTO @@ -1131,6 +1208,12 @@ endif 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 @@ -1163,9 +1246,6 @@ ifdef CONFIG_INTERNAL_AES AESOBJS += src/crypto/aes-internal-enc.c endif endif -ifdef NEED_AES_SIV -AESOBJS += src/crypto/aes-siv.c -endif ifdef NEED_AES OBJS += $(AESOBJS) endif @@ -1173,8 +1253,10 @@ endif SHA1OBJS = ifdef NEED_SHA1 ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) SHA1OBJS += src/crypto/sha1.c endif +endif SHA1OBJS += src/crypto/sha1-prf.c ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += src/crypto/sha1-internal.c @@ -1200,9 +1282,11 @@ endif MD5OBJS = ifndef CONFIG_FIPS ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) MD5OBJS += src/crypto/md5.c endif endif +endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 MD5OBJS += src/crypto/md5-internal.c @@ -1240,8 +1324,10 @@ SHA256OBJS = # none by default ifdef NEED_SHA256 L_CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) SHA256OBJS += src/crypto/sha256.c endif +endif SHA256OBJS += src/crypto/sha256-prf.c ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += src/crypto/sha256-internal.c @@ -1261,12 +1347,34 @@ ifdef NEED_HMAC_SHA256_KDF L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF SHA256OBJS += src/crypto/sha256-kdf.c endif +ifdef NEED_HMAC_SHA384_KDF +L_CFLAGS += -DCONFIG_HMAC_SHA384_KDF +SHA256OBJS += src/crypto/sha384-kdf.c +endif +ifdef NEED_HMAC_SHA512_KDF +L_CFLAGS += -DCONFIG_HMAC_SHA512_KDF +SHA256OBJS += src/crypto/sha512-kdf.c +endif OBJS += $(SHA256OBJS) endif ifdef NEED_SHA384 L_CFLAGS += -DCONFIG_SHA384 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha384.c +endif +endif OBJS += src/crypto/sha384-prf.c endif +ifdef NEED_SHA512 +L_CFLAGS += -DCONFIG_SHA512 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha512.c +endif +endif +OBJS += src/crypto/sha512-prf.c +endif ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c @@ -1317,44 +1425,25 @@ endif OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c endif -ifdef CONFIG_CTRL_IFACE_DBUS -DBUS=y -DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE -DBUS_OBJS += dbus/dbus_old.c dbus/dbus_old_handlers.c -ifdef CONFIG_WPS -DBUS_OBJS += dbus/dbus_old_handlers_wps.c -endif -DBUS_OBJS += dbus/dbus_dict_helpers.c -DBUS_CFLAGS += $(DBUS_INCLUDE) -endif - ifdef CONFIG_CTRL_IFACE_DBUS_NEW -DBUS=y -DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW -DBUS_OBJS ?= dbus/dbus_dict_helpers.c -DBUS_OBJS += dbus/dbus_new_helpers.c -DBUS_OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c +L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW +OBJS += dbus/dbus_dict_helpers.c +OBJS += dbus/dbus_new_helpers.c +OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c +OBJS += dbus/dbus_common.c ifdef CONFIG_WPS -DBUS_OBJS += dbus/dbus_new_handlers_wps.c +OBJS += dbus/dbus_new_handlers_wps.c endif ifdef CONFIG_P2P -DBUS_OBJS += dbus/dbus_new_handlers_p2p.c +OBJS += dbus/dbus_new_handlers_p2p.c endif ifdef CONFIG_CTRL_IFACE_DBUS_INTRO -DBUS_OBJS += dbus/dbus_new_introspect.c -DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO -endif -DBUS_CFLAGS += $(DBUS_INCLUDE) +OBJS += dbus/dbus_new_introspect.c +L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO endif - -ifdef DBUS -DBUS_CFLAGS += -DCONFIG_DBUS -DBUS_OBJS += dbus/dbus_common.c +L_CFLAGS += $(DBUS_INCLUDE) endif -OBJS += $(DBUS_OBJS) -L_CFLAGS += $(DBUS_CFLAGS) - ifdef CONFIG_CTRL_IFACE_BINDER WPA_SUPPLICANT_USE_BINDER=y L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER @@ -1490,6 +1579,12 @@ OBJS += src/utils/ext_password.c L_CFLAGS += -DCONFIG_EXT_PASSWORD endif +ifdef NEED_GAS_SERVER +OBJS += src/common/gas_server.c +L_CFLAGS += -DCONFIG_GAS_SERVER +NEED_GAS=y +endif + ifdef NEED_GAS OBJS += src/common/gas.c OBJS += gas_query.c @@ -1502,6 +1597,11 @@ OBJS += offchannel.c L_CFLAGS += -DCONFIG_OFFCHANNEL endif +ifdef NEED_JSON +OBJS += src/utils/json.c +L_CFLAGS += -DCONFIG_JSON +endif + OBJS += src/drivers/driver_common.c OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c @@ -1580,9 +1680,7 @@ endif # With BoringSSL we need libkeystore-engine in order to provide access to # keystore keys. -ifneq (,$(wildcard external/boringssl/flavor.mk)) LOCAL_SHARED_LIBRARIES += libkeystore-engine -endif ifdef CONFIG_DRIVER_NL80211 ifneq ($(wildcard external/libnl),) diff --git a/contrib/wpa/wpa_supplicant/ChangeLog b/contrib/wpa/wpa_supplicant/ChangeLog index f28055f4093e..89119e7bd18f 100644 --- a/contrib/wpa/wpa_supplicant/ChangeLog +++ b/contrib/wpa/wpa_supplicant/ChangeLog @@ -1,5 +1,144 @@ ChangeLog for wpa_supplicant +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 + [https://w1.fi/security/2017-1/] (CVE-2017-13077, CVE-2017-13078, + CVE-2017-13079, CVE-2017-13080, CVE-2017-13081, CVE-2017-13082, + CVE-2017-13086, CVE-2017-13087, CVE-2017-13088) + * fixed unauthenticated EAPOL-Key decryption in wpa_supplicant + [https://w1.fi/security/2018-1/] (CVE-2018-14526) + * added support for FILS (IEEE 802.11ai) shared key authentication + * added support for OWE (Opportunistic Wireless Encryption, RFC 8110; + and transition mode defined by WFA) + * added support for DPP (Wi-Fi Device Provisioning Protocol) + * added support for RSA 3k key case with Suite B 192-bit level + * fixed Suite B PMKSA caching not to update PMKID during each 4-way + handshake + * fixed EAP-pwd pre-processing with PasswordHashHash + * added EAP-pwd client support for salted passwords + * fixed a regression in TDLS prohibited bit validation + * started to use estimated throughput to avoid undesired signal + strength based roaming decision + * MACsec/MKA: + - new macsec_linux driver interface support for the Linux + kernel macsec module + - number of fixes and extensions + * added support for external persistent storage of PMKSA cache + (PMKSA_GET/PMKSA_ADD control interface commands; and + MESH_PMKSA_GET/MESH_PMKSA_SET for the mesh case) + * fixed mesh channel configuration pri/sec switch case + * added support for beacon report + * large number of other fixes, cleanup, and extensions + * added support for randomizing local address for GAS queries + (gas_rand_mac_addr parameter) + * fixed EAP-SIM/AKA/AKA' ext auth cases within TLS tunnel + * added option for using random WPS UUID (auto_uuid=1) + * added SHA256-hash support for OCSP certificate matching + * fixed EAP-AKA' to add AT_KDF into Synchronization-Failure + * fixed a regression in RSN pre-authentication candidate selection + * added option to configure allowed group management cipher suites + (group_mgmt network profile parameter) + * removed all PeerKey functionality + * fixed nl80211 AP and mesh mode configuration regression with + Linux 4.15 and newer + * added ap_isolate configuration option for AP mode + * added support for nl80211 to offload 4-way handshake into the driver + * added support for using wolfSSL cryptographic library + * SAE + - added support for configuring SAE password separately of the + WPA2 PSK/passphrase + - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection + for SAE; + note: this is not backwards compatible, i.e., both the AP and + station side implementations will need to be update at the same + time to maintain interoperability + - added support for Password Identifier + - fixed FT-SAE PMKID matching + * Hotspot 2.0 + - added support for fetching of Operator Icon Metadata ANQP-element + - added support for Roaming Consortium Selection element + - added support for Terms and Conditions + - added support for OSEN connection in a shared RSN BSS + - added support for fetching Venue URL information + * added support for using OpenSSL 1.1.1 + * FT + - disabled PMKSA caching with FT since it is not fully functional + - added support for SHA384 based AKM + - added support for BIP ciphers BIP-CMAC-256, BIP-GMAC-128, + BIP-GMAC-256 in addition to previously supported BIP-CMAC-128 + - fixed additional IE inclusion in Reassociation Request frame when + using FT protocol + 2016-10-02 - v2.6 * fixed WNM Sleep Mode processing when PMF is not enabled [http://w1.fi/security/2015-6/] (CVE-2015-5310) diff --git a/contrib/wpa/wpa_supplicant/README b/contrib/wpa/wpa_supplicant/README index 11ab01a9c171..bbc86b137424 100644 --- a/contrib/wpa/wpa_supplicant/README +++ b/contrib/wpa/wpa_supplicant/README @@ -1,7 +1,7 @@ -WPA Supplicant +wpa_supplicant ============== -Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with @@ -83,7 +83,7 @@ Supported WPA/IEEE 802.11i features: authentication) (following methods are supported, but since they do not generate keying material, they cannot be used with WPA or IEEE 802.1X WEP keying) - * EAP-MD5-Challenge + * EAP-MD5-Challenge * EAP-MSCHAPv2 * EAP-GTC * EAP-OTP @@ -965,6 +965,17 @@ wpa_priv can control multiple interface with one process, but it is also possible to run multiple wpa_priv processes at the same time, if desired. +It should be noted that the interface used between wpa_supplicant and +wpa_priv does not include all the capabilities of the wpa_supplicant +driver interface and at times, this interface lacks update especially +for recent addition. Consequently, use of wpa_priv does come with the +price of somewhat reduced available functionality. The next section +describing how wpa_supplicant can be used with reduced privileges +without having to handle the complexity of separate wpa_priv. While that +approve does not provide separation for network admin capabilities, it +does allow other root privileges to be dropped without the drawbacks of +the wpa_priv process. + Linux capabilities instead of privileged process ------------------------------------------------ diff --git a/contrib/wpa/wpa_supplicant/README-DPP b/contrib/wpa/wpa_supplicant/README-DPP new file mode 100644 index 000000000000..6496733735d4 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/README-DPP @@ -0,0 +1,195 @@ +Device Provisioning Protocol (DPP) +================================== + +This document describes how the Device Provisioning Protocol (DPP) +implementation in wpa_supplicant and hostapd can be configured and how +the STA device and AP can be configured to connect each other using DPP +Connector mechanism. + +Introduction to DPP +------------------- + +Device provisioning Protocol allows enrolling of interface-less devices +in a secure Wi-Fi network using many methods like QR code based +authentication( detailed below ), PKEX based authentication etc. In DPP +a Configurator is used to provide network credentials to the devices. +The three phases of DPP connection are authentication, configuration and +network introduction. + +Build config setup +------------------ + +The following changes must go in the config file used to compile hostapd +and wpa_supplicant. + +wpa_supplicant build config +--------------------------- + +Enable DPP and protected management frame in wpa_supplicant build config +file + +CONFIG_IEEE80211W=y +CONFIG_DPP=y + +hostapd build config +-------------------- + +Enable DPP and protected management frame in hostapd build config file + +CONFIG_IEEE80211W=y +CONFIG_DPP=y + +Configurator build config +------------------------- + +Any STA or AP device can act as a Configurator. Enable DPP and protected +managment frames in build config. For an AP to act as Configurator, +Interworking needs to be enabled. For wpa_supplicant it is not required. + +CONFIG_INTERWORKING=y + + +Sample supplicant config file before provisioning +------------------------------------------------- + +ctrl_interface=DIR=/var/run/wpa_supplicant +ctrl_interface_group=0 +update_config=1 +pmf=2 +dpp_config_processing=2 + +Sample hostapd config file before provisioning +---------------------------------------------- + +interface=wlan0 +driver=nl80211 +ctrl_interface=/var/run/hostapd +ssid=test +channel=1 +wpa=2 +wpa_key_mgmt=DPP +ieee80211w=1 +wpa_pairwise=CCMP +rsn_pairwise=CCMP + + +Pre-requisites +-------------- + +It is assumed that an AP and client station are up by running hostapd +and wpa_supplicant using respective config files. + + +Creating Configurator +--------------------- + +Add a Configurator over the control interface (wpa_cli/hostapd_cli) + +> dpp_configurator_add +(returns id) + +To get key of Configurator +> dpp_configurator_get_key <id> + + +How to configure an enrollee using Configurator +----------------------------------------------- + +On enrollee side: + +Generate QR code for the device. Store the qr code id returned by the +command. + +> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-channel> key=<key of the device> +(returns bootstrapping info id) + +Get QR Code of device using the bootstrap info id. +> dpp_bootstrap_get_uri <bootstrap-id> + +Make device listen to DPP request (The central frequency of channel 1 is +2412) in case if enrollee is a client device. + +> dpp_listen <frequency> + +On Configurator side: + +Enter the QR Code in the Configurator. +> dpp_qr_code "<QR-Code-read-from-enrollee>" + +On successfully adding QR Code, a bootstrapping info id is returned. + +Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an +AP. conf is sta-dpp if enrollee is a client) +> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id> + +The DPP values will be printed in the console. Save this values into the +config file. If the enrollee is an AP, we need to manually write these +values to the hostapd config file. If the enrollee is a client device, +these details can be automatically saved to config file using the +following command. + +> save_config + +To set values in runtime for AP enrollees + +> set dpp_connector <Connector-value-printed-on-console> +> set dpp_csign <csign-value-on-console> +> set dpp_netaccesskey <netaccess-value-on-console> + +To set values in runtime for client enrollees, set dpp_config_processing +to 2 in wpa_supplicant conf file. + +Once the values are set in run-time (if not set in run-time, but saved +in config files, they are taken up in next restart), the client device +will automatically connect to the already provisioned AP and connection +will be established. + + +Self-configuring a device +------------------------- + +It is possible for a device to configure itself if it is the +Configurator for the network. + +Create a Configurator in the device and use the dpp_configurator_sign +command to get DPP credentials. + +> dpp_configurator_add +(returns configurator id) +> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> + + +Sample AP configuration files after provisioning +------------------------------------------------ + +interface=wlan0 +driver=nl80211 +ctrl_interface=/var/run/hostapd +ssid=test +channel=1 +wpa=2 +wpa_key_mgmt=DPP +ieee80211w=1 +wpa_pairwise=CCMP +rsn_pairwise=CCMP +dpp_connector=<Connector value provided by Configurator> +dpp_csign=<C-Sign-Key value provided by Configurator> +dpp_netaccesskey=<Net access key provided by Configurator> + + +Sample station configuration file after provisioning +---------------------------------------------------- + +ctrl_interface=DIR=/var/run/wpa_supplicant +ctrl_interface_group=0 +update_config=1 +pmf=2 +dpp_config_processing=2 +network={ + ssid="test" + key_mgmt=DPP + ieee80211w=2 + dpp_connector="<Connector value provided by Configurator>" + dpp_netaccesskey=<Net access key provided by Configurator> + dpp_csign=<C-sign-key value provided by Configurator> +} diff --git a/contrib/wpa/wpa_supplicant/README-HS20 b/contrib/wpa/wpa_supplicant/README-HS20 index e4eed2074f91..334287101c92 100644 --- a/contrib/wpa/wpa_supplicant/README-HS20 +++ b/contrib/wpa/wpa_supplicant/README-HS20 @@ -197,6 +197,20 @@ Credentials can be pre-configured for automatic network selection: # pre-configured with the credential since the NAI Realm information # may not be available or fetched. # +# required_roaming_consortium: Required Roaming Consortium OI +# If required_roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that is required to be advertised by the AP for +# the credential to be considered matching. +# +# roaming_consortiums: Roaming Consortium OI(s) memberships +# This string field contains one or more comma delimited OIs (hexdump) +# identifying the roaming consortiums of which the provider is a member. +# The list is sorted from the most preferred one to the least preferred +# one. A match between the Roaming Consortium OIs advertised by an AP and +# the OIs in this list indicates that successful authentication is +# possible. +# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI) +# # eap: Pre-configured EAP method # This optional field can be used to specify which EAP method will be # used with this credential. If not set, the EAP method is selected @@ -295,6 +309,7 @@ Credentials can be pre-configured for automatic network selection: # ca_cert="/etc/wpa_supplicant/ca.pem" # domain="example.com" # roaming_consortium=223344 +# roaming_consortiums="112233,4455667788,aabbcc" # eap=TTLS # phase2="auth=MSCHAPV2" #} @@ -591,7 +606,7 @@ network={ Hotspot 2.0 connection with external network selection ------------------------------------------------------ -When an component controlling wpa_supplicant takes care of Interworking +When a component controlling wpa_supplicant takes care of Interworking network selection, following configuration and network profile parameters can be used to configure a temporary network profile for a Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and @@ -613,6 +628,7 @@ network={ eap=TTLS phase2="auth=MSCHAPV2" update_identifier=54321 + roaming_consortium_selection=112233 #ocsp=2 } @@ -628,4 +644,5 @@ update_identifier: PPS/UpdateIdentifier ca_cert: from the downloaded trust root based on PPS information eap: Credential/UsernamePassword/EAPMethod or NAI Realm list phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list +roaming_consortium_selection: Matching OI from HomeSP/RoamingConsortiumOI ocsp: Credential/CheckAAAServerCertStatus diff --git a/contrib/wpa/wpa_supplicant/README-P2P b/contrib/wpa/wpa_supplicant/README-P2P index 23ac7fa056a4..55a60a296ad7 100644 --- a/contrib/wpa/wpa_supplicant/README-P2P +++ b/contrib/wpa/wpa_supplicant/README-P2P @@ -150,7 +150,7 @@ join-a-group style PD instead of GO Negotiation style PD. p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps] [persistent|persistent=<network id>] [join|auth] - [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto] + [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [he] [provdisc] [auto] [ssid=<hexdump>] Start P2P group formation with a discovered P2P peer. This includes @@ -262,7 +262,7 @@ Parameters definition: session_mac - Mandatory MAC address that owns/initiated the session p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] - [ht40] [vht] + [ht40] [vht] [he] Set up a P2P group owner manually (i.e., without group owner negotiation with a specific peer). This is also known as autonomous @@ -558,7 +558,7 @@ Remove all local services from internal SD query processing. Invitation p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address] - [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht] + [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht] [he] [pref=<MHz>] Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a diff --git a/contrib/wpa/wpa_supplicant/android.config b/contrib/wpa/wpa_supplicant/android.config index 02505bb991aa..6536c110a3ca 100644 --- a/contrib/wpa/wpa_supplicant/android.config +++ b/contrib/wpa/wpa_supplicant/android.config @@ -1,9 +1,9 @@ # Example wpa_supplicant build time configuration # # This file lists the configuration options that are used when building the -# hostapd binary. All lines starting with # are ignored. Configuration option -# lines must be commented out complete, if they are not to be included, i.e., -# just setting VARIABLE=n is not disabling that variable. +# wpa_supplicant binary. All lines starting with # are ignored. Configuration +# option lines must be commented out complete, if they are not to be included, +# i.e., just setting VARIABLE=n is not disabling that variable. # # This file is included in Makefile, so variables like CFLAGS and LIBS can also # be modified from here. In most cases, these lines should use += in order not @@ -91,10 +91,6 @@ CONFIG_EAP_PEAP=y CONFIG_EAP_TTLS=y # EAP-FAST -# Note: Default OpenSSL package does not include support for all the -# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch) -# to add the needed functions. #CONFIG_EAP_FAST=y # EAP-GTC @@ -152,6 +148,9 @@ CONFIG_WPS_NFC=y # EAP-IKEv2 #CONFIG_EAP_IKEV2=y +# EAP-EKE +#CONFIG_EAP_EKE=y + # PKCS#12 (PFX) support (used to read private key and certificate file from # a file that usually has extension .p12 or .pfx) CONFIG_PKCS12=y @@ -176,8 +175,10 @@ CONFIG_SMARTCARD=y # Select control interface backend for external programs, e.g, wpa_cli: # unix = UNIX domain sockets (default for Linux/*BSD) # udp = UDP sockets using localhost (127.0.0.1) +# udp6 = UDP IPv6 sockets using localhost (::1) # named_pipe = Windows Named Pipe (default for Windows) # udp-remote = UDP sockets with remote access (only for tests systems/purpose) +# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose) # y = use default (backwards compatibility) # If this option is commented out, control interface is not included in the # build. @@ -254,6 +255,9 @@ CONFIG_ELOOP=eloop # Should we use epoll instead of select? Select is used by default. #CONFIG_ELOOP_EPOLL=y +# Should we use kqueue instead of select? Select is used by default. +#CONFIG_ELOOP_KQUEUE=y + # Select layer 2 packet implementation # linux = Linux packet socket (default) # pcap = libpcap/libdnet/WinPcap @@ -263,13 +267,19 @@ CONFIG_ELOOP=eloop # none = Empty template CONFIG_L2_PACKET=linux -# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) -CONFIG_PEERKEY=y +# Disable Linux packet socket workaround applicable for station interface +# in a bridge for EAPOL frames. This should be uncommented only if the kernel +# is known to not have the regression issue in packet socket behavior with +# 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 + # Select TLS implementation # openssl = OpenSSL (default) # gnutls = GnuTLS @@ -291,6 +301,10 @@ CONFIG_IEEE80211W=y # will be used) #CONFIG_TLSV12=y +# Select which ciphers to use by default with OpenSSL if the user does not +# specify them. +#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW" + # If CONFIG_TLS=internal is used, additional library and include paths are # needed for LibTomMath. Alternatively, an integrated, minimal version of # LibTomMath can be used. See beginning of libtommath.c for details on benefits @@ -313,10 +327,6 @@ CONFIG_IEEE80211W=y #CONFIG_NDIS_EVENTS_INTEGRATED=y #PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" -# Add support for old DBus control interface -# (fi.epitest.hostap.WPASupplicant) -#CONFIG_CTRL_IFACE_DBUS=y - # Add support for new DBus control interface # (fi.w1.hostap.wpa_supplicant1) #CONFIG_CTRL_IFACE_DBUS_NEW=y @@ -349,7 +359,7 @@ CONFIG_IEEE80211W=y # amount of memory/flash. #CONFIG_DYNAMIC_EAP_METHODS=y -# IEEE Std 802.11r-2008 (Fast BSS Transition) +# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode CONFIG_IEEE80211R=y # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) @@ -424,11 +434,21 @@ CONFIG_ANDROID_LOG=y # disabled. This will save some in binary size and CPU use. However, this # should only be considered for builds that are known to be used on devices # that meet the requirements described above. -#CONFIG_NO_RANDOM_POOL=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 +# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before +# 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) # Note: This is experimental and not complete implementation. CONFIG_WNM=y @@ -442,6 +462,9 @@ CONFIG_INTERWORKING=y # Hotspot 2.0 CONFIG_HS20=y +# Enable interface matching in wpa_supplicant +#CONFIG_MATCH_IFACE=y + # Disable roaming in wpa_supplicant CONFIG_NO_ROAMING=y @@ -460,8 +483,8 @@ CONFIG_P2P=y # Enable TDLS support CONFIG_TDLS=y -# Wi-Fi Direct -# This can be used to enable Wi-Fi Direct extensions for P2P using an external +# Wi-Fi Display +# This can be used to enable Wi-Fi Display extensions for P2P using an external # program to control the additional information exchanges in the messages. CONFIG_WIFI_DISPLAY=y @@ -489,4 +512,34 @@ CONFIG_WIFI_DISPLAY=y # Support Multi Band Operation #CONFIG_MBO=y +# Fast Initial Link Setup (FILS) (IEEE 802.11ai) +#CONFIG_FILS=y + +# Support RSN on IBSS networks +# This is needed to be able to use mode=1 network profile with proto=RSN and +# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None). +#CONFIG_IBSS_RSN=y + +# External PMKSA cache control +# This can be used to enable control interface commands that allow the current +# PMKSA cache entries to be fetched and new entries to be added. +#CONFIG_PMKSA_CACHE_EXTERNAL=y + +# Mesh Networking (IEEE 802.11s) +#CONFIG_MESH=y + +# Background scanning modules +# These can be used to request wpa_supplicant to perform background scanning +# operations for roaming within an ESS (same SSID). See the bgscan parameter in +# the wpa_supplicant.conf file for more details. +# Periodic background scans based on signal strength +#CONFIG_BGSCAN_SIMPLE=y +# Learn channels used by the network and try to avoid bgscans on other +# channels (experimental) +#CONFIG_BGSCAN_LEARN=y + +# Opportunistic Wireless Encryption (OWE) +# Experimental implementation of draft-harkins-owe-07.txt +#CONFIG_OWE=y + include $(wildcard $(LOCAL_PATH)/android_config_*.inc) diff --git a/contrib/wpa/wpa_supplicant/ap.c b/contrib/wpa/wpa_supplicant/ap.c index 5afb772ba192..4e191694296b 100644 --- a/contrib/wpa/wpa_supplicant/ap.c +++ b/contrib/wpa/wpa_supplicant/ap.c @@ -46,23 +46,50 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); #ifdef CONFIG_IEEE80211N static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct hostapd_config *conf, struct hostapd_hw_modes *mode) { #ifdef CONFIG_P2P u8 center_chan = 0; u8 channel = conf->channel; +#endif /* CONFIG_P2P */ if (!conf->secondary_channel) goto no_vht; + /* Use the maximum oper channel width if it's given. */ + if (ssid->max_oper_chwidth) + conf->vht_oper_chwidth = ssid->max_oper_chwidth; + + ieee80211_freq_to_chan(ssid->vht_center_freq2, + &conf->vht_oper_centr_freq_seg1_idx); + + if (!ssid->p2p_group) { + if (!ssid->vht_center_freq1 || + conf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT) + goto no_vht; + ieee80211_freq_to_chan(ssid->vht_center_freq1, + &conf->vht_oper_centr_freq_seg0_idx); + wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP", + conf->vht_oper_centr_freq_seg0_idx); + return; + } + +#ifdef CONFIG_P2P switch (conf->vht_oper_chwidth) { case VHT_CHANWIDTH_80MHZ: case VHT_CHANWIDTH_80P80MHZ: center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); + wpa_printf(MSG_DEBUG, + "VHT center channel %u for 80 or 80+80 MHz bandwidth", + center_chan); break; case VHT_CHANWIDTH_160MHZ: center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel); + wpa_printf(MSG_DEBUG, + "VHT center channel %u for 160 MHz bandwidth", + center_chan); break; default: /* @@ -72,10 +99,17 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, */ conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ; center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel); - if (!center_chan) { + if (center_chan) { + wpa_printf(MSG_DEBUG, + "VHT center channel %u for auto-selected 160 MHz bandwidth", + center_chan); + } else { conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ; center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); + wpa_printf(MSG_DEBUG, + "VHT center channel %u for auto-selected 80 MHz bandwidth", + center_chan); } break; } @@ -83,15 +117,17 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, goto no_vht; conf->vht_oper_centr_freq_seg0_idx = center_chan; + wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO", + conf->vht_oper_centr_freq_seg0_idx); return; +#endif /* CONFIG_P2P */ no_vht: - conf->vht_oper_centr_freq_seg0_idx = - channel + conf->secondary_channel * 2; -#else /* CONFIG_P2P */ + wpa_printf(MSG_DEBUG, + "No VHT higher bandwidth support for the selected channel %d", + conf->channel); conf->vht_oper_centr_freq_seg0_idx = conf->channel + conf->secondary_channel * 2; -#endif /* CONFIG_P2P */ conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT; } #endif /* CONFIG_IEEE80211N */ @@ -123,6 +159,11 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, if (wpa_s->hw.modes) { struct hostapd_hw_modes *mode = NULL; int i, no_ht = 0; + + wpa_printf(MSG_DEBUG, + "Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)", + ssid->frequency, conf->channel); + for (i = 0; i < wpa_s->hw.num_modes; i++) { if (wpa_s->hw.modes[i].mode == conf->hw_mode) { mode = &wpa_s->hw.modes[i]; @@ -131,27 +172,54 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, } #ifdef CONFIG_HT_OVERRIDES - if (ssid->disable_ht) { + if (ssid->disable_ht) + ssid->ht = 0; +#endif /* CONFIG_HT_OVERRIDES */ + + if (!ssid->ht) { + wpa_printf(MSG_DEBUG, + "HT not enabled in network profile"); conf->ieee80211n = 0; conf->ht_capab = 0; no_ht = 1; } -#endif /* CONFIG_HT_OVERRIDES */ if (!no_ht && mode && mode->ht_capab) { + wpa_printf(MSG_DEBUG, + "Enable HT support (p2p_group=%d 11a=%d ht40_hw_capab=%d ssid->ht40=%d)", + ssid->p2p_group, + conf->hw_mode == HOSTAPD_MODE_IEEE80211A, + !!(mode->ht_capab & + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET), + ssid->ht40); conf->ieee80211n = 1; #ifdef CONFIG_P2P - if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && + if (ssid->p2p_group && + conf->hw_mode == HOSTAPD_MODE_IEEE80211A && (mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && - ssid->ht40) + ssid->ht40) { conf->secondary_channel = wpas_p2p_get_ht40_mode(wpa_s, mode, conf->channel); + wpa_printf(MSG_DEBUG, + "HT secondary channel offset %d for P2P group", + conf->secondary_channel); + } +#endif /* CONFIG_P2P */ + + if (!ssid->p2p_group && + (mode->ht_capab & + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { + conf->secondary_channel = ssid->ht40; + wpa_printf(MSG_DEBUG, + "HT secondary channel offset %d for AP", + conf->secondary_channel); + } + if (conf->secondary_channel) conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; -#endif /* CONFIG_P2P */ /* * white-list capabilities that won't cause issues @@ -168,7 +236,8 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, if (mode->vht_capab && ssid->vht) { conf->ieee80211ac = 1; - wpas_conf_ap_vht(wpa_s, conf, mode); + conf->vht_capab |= mode->vht_capab; + wpas_conf_ap_vht(wpa_s, ssid, conf, mode); } } } @@ -229,11 +298,13 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_ACS */ - if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) { + if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes, + wpa_s->hw.num_modes) && wpa_s->conf->country[0]) { conf->ieee80211h = 1; conf->ieee80211d = 1; conf->country[0] = wpa_s->conf->country[0]; conf->country[1] = wpa_s->conf->country[1]; + conf->country[2] = ' '; } #ifdef CONFIG_P2P @@ -265,6 +336,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, conf->supported_rates = list; } +#ifdef CONFIG_IEEE80211AX + if (ssid->mode == WPAS_MODE_P2P_GO || + ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) + conf->ieee80211ax = ssid->he; +#endif /* CONFIG_IEEE80211AX */ + bss->isolate = !wpa_s->conf->p2p_intra_bss; bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; @@ -316,17 +393,34 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i] == 0) continue; - wep->key[i] = os_malloc(ssid->wep_key_len[i]); + wep->key[i] = os_memdup(ssid->wep_key[i], + ssid->wep_key_len[i]); if (wep->key[i] == NULL) return -1; - os_memcpy(wep->key[i], ssid->wep_key[i], - ssid->wep_key_len[i]); wep->len[i] = ssid->wep_key_len[i]; } wep->idx = ssid->wep_tx_keyidx; wep->keys_set = 1; } + if (wpa_s->conf->go_interworking) { + wpa_printf(MSG_DEBUG, + "P2P: Enable Interworking with access_network_type: %d", + wpa_s->conf->go_access_network_type); + bss->interworking = wpa_s->conf->go_interworking; + bss->access_network_type = wpa_s->conf->go_access_network_type; + bss->internet = wpa_s->conf->go_internet; + if (wpa_s->conf->go_venue_group) { + wpa_printf(MSG_DEBUG, + "P2P: Venue group: %d Venue type: %d", + wpa_s->conf->go_venue_group, + wpa_s->conf->go_venue_type); + bss->venue_group = wpa_s->conf->go_venue_group; + bss->venue_type = wpa_s->conf->go_venue_type; + bss->venue_info_set = 1; + } + } + if (ssid->ap_max_inactivity) bss->ap_max_inactivity = ssid->ap_max_inactivity; @@ -406,6 +500,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->ieee80211w = ssid->ieee80211w; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + bss->ocv = ssid->ocv; +#endif /* CONFIG_OCV */ + #ifdef CONFIG_WPS /* * Enable WPS by default for open and WPA/WPA2-Personal network, but @@ -461,6 +559,9 @@ no_wps: else bss->max_num_sta = wpa_s->conf->max_num_sta; + if (!bss->isolate) + bss->isolate = wpa_s->conf->ap_isolate; + bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack; if (wpa_s->conf->ap_vendor_elements) { @@ -585,9 +686,18 @@ static void wpas_ap_configured_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; + wpa_printf(MSG_DEBUG, "AP interface setup completed - state %s", + hostapd_state_text(wpa_s->ap_iface->state)); + if (wpa_s->ap_iface->state == HAPD_IFACE_DISABLED) { + wpa_supplicant_ap_deinit(wpa_s); + return; + } + #ifdef CONFIG_ACS - if (wpa_s->current_ssid && wpa_s->current_ssid->acs) + if (wpa_s->current_ssid && wpa_s->current_ssid->acs) { wpa_s->assoc_freq = wpa_s->ap_iface->freq; + wpa_s->current_ssid->frequency = wpa_s->ap_iface->freq; + } #endif /* CONFIG_ACS */ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); @@ -662,7 +772,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, else params.uapsd = -1; - if (ieee80211_is_dfs(params.freq.freq)) + if (ieee80211_is_dfs(params.freq.freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) params.freq.freq = 0; /* set channel after CAC */ if (params.p2p) @@ -692,13 +803,6 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, return -1; } - /* Use the maximum oper channel width if it's given. */ - if (ssid->max_oper_chwidth) - conf->vht_oper_chwidth = ssid->max_oper_chwidth; - - ieee80211_freq_to_chan(ssid->vht_center_freq2, - &conf->vht_oper_centr_freq_seg1_idx); - os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params, wpa_s->conf->wmm_ac_params, sizeof(wpa_s->conf->wmm_ac_params)); @@ -777,6 +881,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN); wpa_s->assoc_freq = ssid->frequency; +#if defined(CONFIG_P2P) && defined(CONFIG_ACS) + if (wpa_s->p2p_go_do_acs) { + wpa_s->ap_iface->conf->channel = 0; + wpa_s->ap_iface->conf->hw_mode = wpa_s->p2p_go_acs_band; + ssid->acs = 1; + } +#endif /* CONFIG_P2P && CONFIG_ACS */ + if (hostapd_setup_interface(wpa_s->ap_iface)) { wpa_printf(MSG_ERROR, "Failed to initialize AP interface"); wpa_supplicant_ap_deinit(wpa_s); @@ -1277,13 +1389,16 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos) void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, int offset, int width, int cf1, int cf2) { - if (!wpa_s->ap_iface) - return; + struct hostapd_iface *iface = wpa_s->ap_iface; + if (!iface) + iface = wpa_s->ifmsh; + if (!iface) + return; wpa_s->assoc_freq = freq; if (wpa_s->current_ssid) wpa_s->current_ssid->frequency = freq; - hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, + hostapd_event_ch_switch(iface->bss[0], freq, ht, offset, width, cf1, cf2); } @@ -1436,66 +1551,123 @@ void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s) if (wpa_s->ifmsh) hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]); } + + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + +int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr, + char *buf, size_t len) +{ + return hostapd_ctrl_iface_pmksa_list_mesh(wpa_s->ifmsh->bss[0], addr, + &buf[0], len); +} + + +int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd) +{ + struct external_pmksa_cache *entry; + void *pmksa_cache; + + pmksa_cache = hostapd_ctrl_iface_pmksa_create_entry(wpa_s->own_addr, + cmd); + if (!pmksa_cache) + return -1; + + entry = os_zalloc(sizeof(struct external_pmksa_cache)); + if (!entry) + return -1; + + entry->pmksa_cache = pmksa_cache; + + dl_list_add(&wpa_s->mesh_external_pmksa_cache, &entry->list); + + return 0; +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + #endif /* CONFIG_CTRL_IFACE */ #ifdef NEED_AP_MLME -void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, - struct dfs_event *radar) +void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) { - if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) + struct hostapd_iface *iface = wpa_s->ap_iface; + + if (!iface) + iface = wpa_s->ifmsh; + if (!iface || !iface->bss[0]) return; wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); - hostapd_dfs_radar_detected(wpa_s->ap_iface, radar->freq, + hostapd_dfs_radar_detected(iface, radar->freq, radar->ht_enabled, radar->chan_offset, radar->chan_width, radar->cf1, radar->cf2); } -void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s, - struct dfs_event *radar) +void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) { - if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) + struct hostapd_iface *iface = wpa_s->ap_iface; + + if (!iface) + iface = wpa_s->ifmsh; + if (!iface || !iface->bss[0]) return; wpa_printf(MSG_DEBUG, "DFS CAC started on %d MHz", radar->freq); - hostapd_dfs_start_cac(wpa_s->ap_iface, radar->freq, + hostapd_dfs_start_cac(iface, radar->freq, radar->ht_enabled, radar->chan_offset, radar->chan_width, radar->cf1, radar->cf2); } -void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s, - struct dfs_event *radar) +void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) { - if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) + struct hostapd_iface *iface = wpa_s->ap_iface; + + if (!iface) + iface = wpa_s->ifmsh; + if (!iface || !iface->bss[0]) return; wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); - hostapd_dfs_complete_cac(wpa_s->ap_iface, 1, radar->freq, + hostapd_dfs_complete_cac(iface, 1, radar->freq, radar->ht_enabled, radar->chan_offset, radar->chan_width, radar->cf1, radar->cf2); } -void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s, - struct dfs_event *radar) +void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) { - if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) + struct hostapd_iface *iface = wpa_s->ap_iface; + + if (!iface) + iface = wpa_s->ifmsh; + if (!iface || !iface->bss[0]) return; wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); - hostapd_dfs_complete_cac(wpa_s->ap_iface, 0, radar->freq, + hostapd_dfs_complete_cac(iface, 0, radar->freq, radar->ht_enabled, radar->chan_offset, radar->chan_width, radar->cf1, radar->cf2); } -void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s, - struct dfs_event *radar) +void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) { - if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) + struct hostapd_iface *iface = wpa_s->ap_iface; + + if (!iface) + iface = wpa_s->ifmsh; + if (!iface || !iface->bss[0]) return; wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); - hostapd_dfs_nop_finished(wpa_s->ap_iface, radar->freq, + hostapd_dfs_nop_finished(iface, radar->freq, radar->ht_enabled, radar->chan_offset, radar->chan_width, radar->cf1, radar->cf2); } diff --git a/contrib/wpa/wpa_supplicant/ap.h b/contrib/wpa/wpa_supplicant/ap.h index 5a59ddcc1c93..447b551863a3 100644 --- a/contrib/wpa/wpa_supplicant/ap.h +++ b/contrib/wpa/wpa_supplicant/ap.h @@ -85,17 +85,20 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s); int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len); void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s); +int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr, + char *buf, size_t len); +int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd); -void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, +void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, + struct dfs_event *radar); +void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s, struct dfs_event *radar); -void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s, - struct dfs_event *radar); -void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s, - struct dfs_event *radar); -void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s, - struct dfs_event *radar); -void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s, - struct dfs_event *radar); +void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s, + struct dfs_event *radar); +void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s, + struct dfs_event *radar); +void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s, + struct dfs_event *radar); void ap_periodic(struct wpa_supplicant *wpa_s); diff --git a/contrib/wpa/wpa_supplicant/autoscan.c b/contrib/wpa/wpa_supplicant/autoscan.c index 072a1d5414ae..5056a9300a87 100644 --- a/contrib/wpa/wpa_supplicant/autoscan.c +++ b/contrib/wpa/wpa_supplicant/autoscan.c @@ -47,11 +47,16 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) struct sched_scan_plan *scan_plans; /* Give preference to scheduled scan plans if supported/configured */ - if (wpa_s->sched_scan_plans) + if (wpa_s->sched_scan_plans) { + wpa_printf(MSG_DEBUG, + "autoscan: sched_scan_plans set - use it instead"); return 0; + } - if (wpa_s->autoscan && wpa_s->autoscan_priv) + if (wpa_s->autoscan && wpa_s->autoscan_priv) { + wpa_printf(MSG_DEBUG, "autoscan: Already initialized"); return 0; + } if (name == NULL) return 0; diff --git a/contrib/wpa/wpa_supplicant/bgscan.c b/contrib/wpa/wpa_supplicant/bgscan.c index 798b43c3fdf7..1ea640114c8e 100644 --- a/contrib/wpa/wpa_supplicant/bgscan.c +++ b/contrib/wpa/wpa_supplicant/bgscan.c @@ -34,8 +34,6 @@ int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const struct bgscan_ops *ops = NULL; bgscan_deinit(wpa_s); - if (name == NULL) - return -1; params = os_strchr(name, ':'); if (params == NULL) { diff --git a/contrib/wpa/wpa_supplicant/bgscan_learn.c b/contrib/wpa/wpa_supplicant/bgscan_learn.c index a320cc43068c..cb732f709b9e 100644 --- a/contrib/wpa/wpa_supplicant/bgscan_learn.c +++ b/contrib/wpa/wpa_supplicant/bgscan_learn.c @@ -320,9 +320,6 @@ static int bgscan_learn_get_params(struct bgscan_learn_data *data, { const char *pos; - if (params == NULL) - return 0; - data->short_interval = atoi(params); pos = os_strchr(params, ':'); diff --git a/contrib/wpa/wpa_supplicant/bgscan_simple.c b/contrib/wpa/wpa_supplicant/bgscan_simple.c index a467cc5b9271..41a26df0d635 100644 --- a/contrib/wpa/wpa_supplicant/bgscan_simple.c +++ b/contrib/wpa/wpa_supplicant/bgscan_simple.c @@ -56,12 +56,7 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) } else { if (data->scan_interval == data->short_interval) { data->short_scan_count++; - /* - * Spend at most the duration of a long scan interval - * scanning at the short scan interval. After that, - * revert to the long scan interval. - */ - if (data->short_scan_count > data->max_short_scans) { + if (data->short_scan_count >= data->max_short_scans) { data->scan_interval = data->long_interval; wpa_printf(MSG_DEBUG, "bgscan simple: Backing " "off to long scan interval"); @@ -85,9 +80,6 @@ static int bgscan_simple_get_params(struct bgscan_simple_data *data, { const char *pos; - if (params == NULL) - return 0; - data->short_interval = atoi(params); pos = os_strchr(params, ':'); diff --git a/contrib/wpa/wpa_supplicant/bss.c b/contrib/wpa/wpa_supplicant/bss.c index 3a8778db9058..9b19f37affa0 100644 --- a/contrib/wpa/wpa_supplicant/bss.c +++ b/contrib/wpa/wpa_supplicant/bss.c @@ -1,6 +1,6 @@ /* * BSS table - * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -93,6 +93,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) ANQP_DUP(nai_realm); ANQP_DUP(anqp_3gpp); ANQP_DUP(domain_name); + ANQP_DUP(fils_realm_info); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 ANQP_DUP(hs20_capability_list); @@ -101,6 +102,8 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) ANQP_DUP(hs20_connection_capability); ANQP_DUP(hs20_operating_class); ANQP_DUP(hs20_osu_providers_list); + ANQP_DUP(hs20_operator_icon_metadata); + ANQP_DUP(hs20_osu_providers_nai_list); #endif /* CONFIG_HS20 */ #undef ANQP_DUP @@ -168,6 +171,7 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) wpabuf_free(anqp->nai_realm); wpabuf_free(anqp->anqp_3gpp); wpabuf_free(anqp->domain_name); + wpabuf_free(anqp->fils_realm_info); while ((elem = dl_list_first(&anqp->anqp_elems, struct wpa_bss_anqp_elem, list))) { @@ -183,6 +187,8 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) wpabuf_free(anqp->hs20_connection_capability); wpabuf_free(anqp->hs20_operating_class); wpabuf_free(anqp->hs20_osu_providers_list); + wpabuf_free(anqp->hs20_operator_icon_metadata); + wpabuf_free(anqp->hs20_osu_providers_nai_list); #endif /* CONFIG_HS20 */ os_free(anqp); @@ -267,9 +273,9 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, } -static void calculate_update_time(const struct os_reltime *fetch_time, - unsigned int age_ms, - struct os_reltime *update_time) +void calculate_update_time(const struct os_reltime *fetch_time, + unsigned int age_ms, + struct os_reltime *update_time) { os_time_t usec; @@ -595,6 +601,42 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, { u32 changes; + if (bss->last_update_idx == wpa_s->bss_update_idx) { + struct os_reltime update_time; + + /* + * Some drivers (e.g., cfg80211) include multiple BSS entries + * for the same BSS if that BSS's channel changes. The BSS list + * implementation in wpa_supplicant does not do that and we need + * to filter out the obsolete results here to make sure only the + * most current BSS information remains in the table. + */ + wpa_printf(MSG_DEBUG, "BSS: " MACSTR + " has multiple entries in the scan results - select the most current one", + MAC2STR(bss->bssid)); + calculate_update_time(fetch_time, res->age, &update_time); + wpa_printf(MSG_DEBUG, + "Previous last_update: %u.%06u (freq %d%s)", + (unsigned int) bss->last_update.sec, + (unsigned int) bss->last_update.usec, + bss->freq, + (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : ""); + wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)", + (unsigned int) update_time.sec, + (unsigned int) update_time.usec, + res->freq, + (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : ""); + if ((bss->flags & WPA_BSS_ASSOCIATED) || + (!(res->flags & WPA_SCAN_ASSOCIATED) && + !os_reltime_before(&bss->last_update, &update_time))) { + wpa_printf(MSG_DEBUG, + "Ignore this BSS entry since the previous update looks more current"); + return bss; + } + wpa_printf(MSG_DEBUG, + "Accept this BSS entry since it looks more current than the previous update"); + } + changes = wpa_bss_compare_res(bss, res); if (changes & WPA_BSS_FREQ_CHANGED_FLAG) wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d", @@ -1279,3 +1321,26 @@ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates) *rates = r; return len; } + + +#ifdef CONFIG_FILS +const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss) +{ + const u8 *ie; + + if (bss) { + ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); + if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7)) + return ie + 4; + } + + return NULL; +} +#endif /* CONFIG_FILS */ + + +int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab) +{ + return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB), + capab); +} diff --git a/contrib/wpa/wpa_supplicant/bss.h b/contrib/wpa/wpa_supplicant/bss.h index 84e8fb07461e..3ce8cd3f429a 100644 --- a/contrib/wpa/wpa_supplicant/bss.h +++ b/contrib/wpa/wpa_supplicant/bss.h @@ -1,6 +1,6 @@ /* * BSS table - * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -40,6 +40,7 @@ struct wpa_bss_anqp { struct wpabuf *nai_realm; struct wpabuf *anqp_3gpp; struct wpabuf *domain_name; + struct wpabuf *fils_realm_info; struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */ #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 @@ -49,6 +50,8 @@ struct wpa_bss_anqp { struct wpabuf *hs20_connection_capability; struct wpabuf *hs20_operating_class; struct wpabuf *hs20_osu_providers_list; + struct wpabuf *hs20_operator_icon_metadata; + struct wpabuf *hs20_osu_providers_nai_list; #endif /* CONFIG_HS20 */ }; @@ -144,6 +147,8 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss); int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates); struct wpa_bss_anqp * wpa_bss_anqp_alloc(void); int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss); +const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss); +int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab); static inline int bss_is_dmg(const struct wpa_bss *bss) { @@ -167,4 +172,8 @@ static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level) bss->level = new_level; } +void calculate_update_time(const struct os_reltime *fetch_time, + unsigned int age_ms, + struct os_reltime *update_time); + #endif /* BSS_H */ diff --git a/contrib/wpa/wpa_supplicant/config.c b/contrib/wpa/wpa_supplicant/config.c index dd922caf80af..2058175f885e 100644 --- a/contrib/wpa/wpa_supplicant/config.c +++ b/contrib/wpa/wpa_supplicant/config.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration parser and common functions - * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -11,6 +11,7 @@ #include "common.h" #include "utils/uuid.h" #include "utils/ip_addr.h" +#include "common/ieee802_1x_defs.h" #include "crypto/sha1.h" #include "rsn_supp/wpa.h" #include "eap_peer/eap.h" @@ -396,6 +397,50 @@ static char * wpa_config_write_bssid(const struct parse_data *data, #endif /* NO_CONFIG_WRITE */ +static int wpa_config_parse_bssid_hint(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || + os_strcmp(value, "any") == 0) { + ssid->bssid_hint_set = 0; + wpa_printf(MSG_MSGDUMP, "BSSID hint any"); + return 0; + } + if (hwaddr_aton(value, ssid->bssid_hint)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID hint '%s'.", + line, value); + return -1; + } + ssid->bssid_hint_set = 1; + wpa_hexdump(MSG_MSGDUMP, "BSSID hint", ssid->bssid_hint, ETH_ALEN); + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_bssid_hint(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value; + int res; + + if (!ssid->bssid_hint_set) + return NULL; + + value = os_malloc(20); + if (!value) + return NULL; + res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid_hint)); + if (os_snprintf_error(20, res)) { + os_free(value); + return NULL; + } + return value; +} +#endif /* NO_CONFIG_WRITE */ + + static int wpa_config_parse_bssid_blacklist(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) @@ -690,6 +735,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, val |= WPA_KEY_MGMT_FT_PSK; else if (os_strcmp(start, "FT-EAP") == 0) val |= WPA_KEY_MGMT_FT_IEEE8021X; +#ifdef CONFIG_SHA384 + else if (os_strcmp(start, "FT-EAP-SHA384") == 0) + val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384; +#endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) @@ -719,6 +768,26 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0) val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; #endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_FILS + else if (os_strcmp(start, "FILS-SHA256") == 0) + val |= WPA_KEY_MGMT_FILS_SHA256; + else if (os_strcmp(start, "FILS-SHA384") == 0) + val |= WPA_KEY_MGMT_FILS_SHA384; +#ifdef CONFIG_IEEE80211R + else if (os_strcmp(start, "FT-FILS-SHA256") == 0) + val |= WPA_KEY_MGMT_FT_FILS_SHA256; + else if (os_strcmp(start, "FT-FILS-SHA384") == 0) + val |= WPA_KEY_MGMT_FT_FILS_SHA384; +#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_FILS */ +#ifdef CONFIG_OWE + else if (os_strcmp(start, "OWE") == 0) + val |= WPA_KEY_MGMT_OWE; +#endif /* CONFIG_OWE */ +#ifdef CONFIG_DPP + else if (os_strcmp(start, "DPP") == 0) + val |= WPA_KEY_MGMT_DPP; +#endif /* CONFIG_DPP */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); @@ -827,6 +896,18 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, } pos += ret; } + +#ifdef CONFIG_SHA384 + if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W @@ -921,6 +1002,71 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, } #endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_FILS + if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, "%sFILS-SHA256", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFILS-SHA384", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#ifdef CONFIG_IEEE80211R + if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_FILS */ + +#ifdef CONFIG_DPP + if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) { + ret = os_snprintf(pos, end - pos, "%sDPP", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#endif /* CONFIG_DPP */ + +#ifdef CONFIG_OWE + if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) { + ret = os_snprintf(pos, end - pos, "%sOWE", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#endif /* CONFIG_OWE */ + if (pos == buf) { os_free(buf); buf = NULL; @@ -1042,6 +1188,40 @@ static char * wpa_config_write_group(const struct parse_data *data, #endif /* NO_CONFIG_WRITE */ +static int wpa_config_parse_group_mgmt(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int val; + + val = wpa_config_parse_cipher(line, value); + if (val == -1) + return -1; + + if (val & ~WPA_ALLOWED_GROUP_MGMT_CIPHERS) { + wpa_printf(MSG_ERROR, + "Line %d: not allowed group management cipher (0x%x).", + line, val); + return -1; + } + + if (ssid->group_mgmt_cipher == val) + return 1; + wpa_printf(MSG_MSGDUMP, "group_mgmt: 0x%x", val); + ssid->group_mgmt_cipher = val; + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_group_mgmt(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_cipher(ssid->group_mgmt_cipher); +} +#endif /* NO_CONFIG_WRITE */ + + static int wpa_config_parse_auth_alg(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) @@ -1816,6 +1996,140 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data, #endif /* CONFIG_MESH */ +#ifdef CONFIG_MACSEC + +static int wpa_config_parse_mka_cak(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + size_t len; + + len = os_strlen(value); + if (len > 2 * MACSEC_CAK_MAX_LEN || + (len != 2 * 16 && len != 2 * 32) || + hexstr2bin(value, ssid->mka_cak, len / 2)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.", + line, value); + return -1; + } + ssid->mka_cak_len = len / 2; + ssid->mka_psk_set |= MKA_PSK_SET_CAK; + + wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, + ssid->mka_cak_len); + return 0; +} + + +static int wpa_config_parse_mka_ckn(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + size_t len; + + len = os_strlen(value); + if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */ + len < 2 || /* too short */ + len % 2 != 0 /* not an integral number of bytes */) { + wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.", + line, value); + return -1; + } + ssid->mka_ckn_len = len / 2; + if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.", + line, value); + return -1; + } + + ssid->mka_psk_set |= MKA_PSK_SET_CKN; + + wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, + ssid->mka_ckn_len); + return 0; +} + + +#ifndef NO_CONFIG_WRITE + +static char * wpa_config_write_mka_cak(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK)) + return NULL; + + return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len); +} + + +static char * wpa_config_write_mka_ckn(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN)) + return NULL; + return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len); +} + +#endif /* NO_CONFIG_WRITE */ + +#endif /* CONFIG_MACSEC */ + + +#ifdef CONFIG_OCV + +static int wpa_config_parse_ocv(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + char *end; + + ssid->ocv = strtol(value, &end, 0); + if (*end || ssid->ocv < 0 || ssid->ocv > 1) { + wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.", + line, value); + return -1; + } + if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) + ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_ocv(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value = os_malloc(20); + + if (!value) + return NULL; + os_snprintf(value, 20, "%d", ssid->ocv); + value[20 - 1] = '\0'; + return value; +} +#endif /* NO_CONFIG_WRITE */ + +#endif /* CONFIG_OCV */ + + +static int wpa_config_parse_peerkey(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored"); + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_peerkey(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return NULL; +} +#endif /* NO_CONFIG_WRITE */ + + /* Helper macros for network block parser */ #ifdef OFFSET @@ -1907,24 +2221,34 @@ static const struct parse_data ssid_fields[] = { { STR_RANGE(ssid, 0, SSID_MAX_LEN) }, { INT_RANGE(scan_ssid, 0, 1) }, { FUNC(bssid) }, + { FUNC(bssid_hint) }, { FUNC(bssid_blacklist) }, { FUNC(bssid_whitelist) }, { FUNC_KEY(psk) }, { INT(mem_only_psk) }, + { STR_KEY(sae_password) }, + { STR(sae_password_id) }, { FUNC(proto) }, { FUNC(key_mgmt) }, { INT(bg_scan_period) }, { FUNC(pairwise) }, { FUNC(group) }, + { FUNC(group_mgmt) }, { FUNC(auth_alg) }, { FUNC(scan_freq) }, { FUNC(freq_list) }, + { 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(vht_center_freq1) }, + { INT(vht_center_freq2) }, #ifdef IEEE8021X_EAPOL { FUNC(eap) }, { STR_LENe(identity) }, { STR_LENe(anonymous_identity) }, + { STR_LENe(imsi_identity) }, { FUNC_KEY(password) }, { STRe(ca_cert) }, { STRe(ca_path) }, @@ -1933,6 +2257,7 @@ static const struct parse_data ssid_fields[] = { { 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) }, @@ -1943,6 +2268,7 @@ static const struct parse_data ssid_fields[] = { { 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) }, @@ -1981,6 +2307,7 @@ static const struct parse_data ssid_fields[] = { #ifdef CONFIG_MESH { INT_RANGE(mode, 0, 5) }, { INT_RANGE(no_auto_peer, 0, 1) }, + { INT_RANGE(mesh_rssi_threshold, -255, 1) }, #else /* CONFIG_MESH */ { INT_RANGE(mode, 0, 4) }, #endif /* CONFIG_MESH */ @@ -1990,7 +2317,10 @@ static const struct parse_data ssid_fields[] = { #ifdef CONFIG_IEEE80211W { INT_RANGE(ieee80211w, 0, 2) }, #endif /* CONFIG_IEEE80211W */ - { INT_RANGE(peerkey, 0, 1) }, +#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(fixed_freq, 0, 1) }, @@ -2019,6 +2349,8 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(disable_sgi, 0, 1) }, { INT_RANGE(disable_ldpc, 0, 1) }, { INT_RANGE(ht40_intolerant, 0, 1) }, + { INT_RANGE(tx_stbc, -1, 1) }, + { INT_RANGE(rx_stbc, -1, 3) }, { INT_RANGE(disable_max_amsdu, -1, 1) }, { INT_RANGE(ampdu_factor, -1, 3) }, { INT_RANGE(ampdu_density, -1, 7) }, @@ -2050,13 +2382,31 @@ static const struct parse_data ssid_fields[] = { { INT(beacon_int) }, #ifdef CONFIG_MACSEC { INT_RANGE(macsec_policy, 0, 1) }, + { INT_RANGE(macsec_integ_only, 0, 1) }, + { INT_RANGE(macsec_replay_protect, 0, 1) }, + { INT(macsec_replay_window) }, + { INT_RANGE(macsec_port, 1, 65534) }, + { INT_RANGE(mka_priority, 0, 255) }, + { FUNC_KEY(mka_cak) }, + { FUNC_KEY(mka_ckn) }, #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 { INT(update_identifier) }, + { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) }, #endif /* CONFIG_HS20 */ { INT_RANGE(mac_addr, 0, 2) }, { INT_RANGE(pbss, 0, 2) }, { INT_RANGE(wps_disabled, 0, 1) }, + { INT_RANGE(fils_dh_group, 0, 65535) }, +#ifdef CONFIG_DPP + { STR(dpp_connector) }, + { STR_LEN(dpp_netaccesskey) }, + { INT(dpp_netaccesskey_expiry) }, + { STR_LEN(dpp_csign) }, +#endif /* CONFIG_DPP */ + { INT_RANGE(owe_group, 0, 65535) }, + { INT_RANGE(owe_only, 0, 1) }, + { INT_RANGE(multi_ap_backhaul_sta, 0, 1) }, }; #undef OFFSET @@ -2168,6 +2518,7 @@ 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); bin_clear_free(eap->password, eap->password_len); os_free(eap->ca_cert); os_free(eap->ca_path); @@ -2176,6 +2527,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap) 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); @@ -2186,6 +2538,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap) 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); @@ -2226,6 +2579,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid) os_free(ssid->ssid); str_clear_free(ssid->passphrase); os_free(ssid->ext_psk); + str_clear_free(ssid->sae_password); + os_free(ssid->sae_password_id); #ifdef IEEE8021X_EAPOL eap_peer_config_free(&ssid->eap); #endif /* IEEE8021X_EAPOL */ @@ -2242,6 +2597,12 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid) #ifdef CONFIG_MESH os_free(ssid->mesh_basic_rates); #endif /* CONFIG_MESH */ +#ifdef CONFIG_HS20 + os_free(ssid->roaming_consortium_selection); +#endif /* CONFIG_HS20 */ + os_free(ssid->dpp_connector); + bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len); + os_free(ssid->dpp_csign); while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry, list))) { dl_list_del(&psk->list); @@ -2495,6 +2856,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->group_cipher = DEFAULT_GROUP; ssid->key_mgmt = DEFAULT_KEY_MGMT; ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; + ssid->ht = 1; #ifdef IEEE8021X_EAPOL ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; @@ -2506,12 +2868,15 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT; ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT; ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT; + ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD; #endif /* CONFIG_MESH */ #ifdef CONFIG_HT_OVERRIDES ssid->disable_ht = DEFAULT_DISABLE_HT; ssid->disable_ht40 = DEFAULT_DISABLE_HT40; ssid->disable_sgi = DEFAULT_DISABLE_SGI; ssid->disable_ldpc = DEFAULT_DISABLE_LDPC; + ssid->tx_stbc = DEFAULT_TX_STBC; + ssid->rx_stbc = DEFAULT_RX_STBC; ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU; ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR; ssid->ampdu_density = DEFAULT_AMPDU_DENSITY; @@ -2538,7 +2903,11 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) #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 */ ssid->mac_addr = -1; + ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH; } @@ -2849,11 +3218,64 @@ static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred, } +static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred, + const char *value) +{ + u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; + size_t roaming_consortiums_len[MAX_ROAMING_CONS]; + unsigned int num_roaming_consortiums = 0; + const char *pos, *end; + size_t len; + + os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums)); + os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len)); + + for (pos = value;;) { + end = os_strchr(pos, ','); + len = end ? (size_t) (end - pos) : os_strlen(pos); + if (!end && len == 0) + break; + if (len == 0 || (len & 1) != 0 || + len / 2 > MAX_ROAMING_CONS_OI_LEN || + hexstr2bin(pos, + roaming_consortiums[num_roaming_consortiums], + len / 2) < 0) { + wpa_printf(MSG_INFO, + "Invalid roaming_consortiums entry: %s", + pos); + return -1; + } + roaming_consortiums_len[num_roaming_consortiums] = len / 2; + num_roaming_consortiums++; + + if (!end) + break; + + if (num_roaming_consortiums >= MAX_ROAMING_CONS) { + wpa_printf(MSG_INFO, + "Too many roaming_consortiums OIs"); + return -1; + } + + pos = end + 1; + } + + os_memcpy(cred->roaming_consortiums, roaming_consortiums, + sizeof(roaming_consortiums)); + os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len, + sizeof(roaming_consortiums_len)); + cred->num_roaming_consortiums = num_roaming_consortiums; + + return 0; +} + + int wpa_config_set_cred(struct wpa_cred *cred, const char *var, const char *value, int line) { char *val; size_t len; + int res; if (os_strcmp(var, "temporary") == 0) { cred->temporary = atoi(value); @@ -3076,6 +3498,16 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "roaming_consortiums") == 0) { + res = wpa_config_set_cred_roaming_consortiums(cred, val); + if (res < 0) + wpa_printf(MSG_ERROR, + "Line %d: invalid roaming_consortiums", + line); + os_free(val); + return res; + } + if (os_strcmp(var, "excluded_ssid") == 0) { struct excluded_ssid *e; @@ -3387,6 +3819,31 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) return buf; } + if (os_strcmp(var, "roaming_consortiums") == 0) { + size_t buflen; + char *buf, *pos; + size_t i; + + if (!cred->num_roaming_consortiums) + return NULL; + buflen = cred->num_roaming_consortiums * + MAX_ROAMING_CONS_OI_LEN * 2 + 1; + buf = os_malloc(buflen); + if (!buf) + return NULL; + pos = buf; + for (i = 0; i < cred->num_roaming_consortiums; i++) { + if (i > 0) + *pos++ = ','; + pos += wpa_snprintf_hex( + pos, buf + buflen - pos, + cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i]); + } + *pos = '\0'; + return buf; + } + if (os_strcmp(var, "excluded_ssid") == 0) { unsigned int i; char *buf, *end, *pos; @@ -3644,6 +4101,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; config->max_num_sta = DEFAULT_MAX_NUM_STA; + config->ap_isolate = DEFAULT_AP_ISOLATE; config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE; config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ; config->wmm_ac_params[0] = ac_be; @@ -3658,12 +4116,16 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, #ifdef CONFIG_MBO config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA; + config->disassoc_imminent_rssi_threshold = + DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD; + config->oce = DEFAULT_OCE_SUPPORT; #endif /* CONFIG_MBO */ if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); if (driver_param) config->driver_param = os_strdup(driver_param); + config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; return config; } @@ -4070,6 +4532,21 @@ static int wpa_config_process_p2p_no_go_freq( return 0; } + +static int wpa_config_process_p2p_device_persistent_mac_addr( + const struct global_parse_data *data, + struct wpa_config *config, int line, const char *pos) +{ + if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid p2p_device_persistent_mac_addr '%s'", + line, pos); + return -1; + } + + return 0; +} + #endif /* CONFIG_P2P */ @@ -4269,6 +4746,7 @@ static const struct global_parse_data global_fields[] = { { FUNC_NO_VAR(load_dynamic_eap), 0 }, #ifdef CONFIG_WPS { FUNC(uuid), CFG_CHANGED_UUID }, + { INT_RANGE(auto_uuid, 0, 1), 0 }, { STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN), CFG_CHANGED_DEVICE_NAME }, { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING }, @@ -4279,6 +4757,7 @@ static const struct global_parse_data global_fields[] = { { FUNC(os_version), CFG_CHANGED_OS_VERSION }, { STR(config_methods), CFG_CHANGED_CONFIG_METHODS }, { INT_RANGE(wps_cred_processing, 0, 2), 0 }, + { INT_RANGE(wps_cred_add_sae, 0, 1), 0 }, { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P @@ -4301,6 +4780,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 }, { INT(p2p_go_ht40), 0 }, { INT(p2p_go_vht), 0 }, + { INT(p2p_go_he), 0 }, { INT(p2p_disabled), 0 }, { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 }, { INT(p2p_no_group_iface), 0 }, @@ -4310,6 +4790,9 @@ static const struct global_parse_data global_fields[] = { { IPV4(ip_addr_start), 0 }, { IPV4(ip_addr_end), 0 }, { INT_RANGE(p2p_cli_probe, 0, 1), 0 }, + { INT(p2p_device_random_mac_addr), 0 }, + { FUNC(p2p_device_persistent_mac_addr), 0 }, + { INT(p2p_interface_random_mac_addr), 0 }, #endif /* CONFIG_P2P */ { FUNC(country), CFG_CHANGED_COUNTRY }, { INT(bss_max_count), 0 }, @@ -4318,6 +4801,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(filter_ssids, 0, 1), 0 }, { INT_RANGE(filter_rssi, -100, 0), 0 }, { INT(max_num_sta), 0 }, + { INT_RANGE(ap_isolate, 0, 1), 0 }, { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, #ifdef CONFIG_HS20 { INT_RANGE(hs20, 0, 1), 0 }, @@ -4325,6 +4809,11 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(interworking, 0, 1), 0 }, { FUNC(hessid), 0 }, { INT_RANGE(access_network_type, 0, 15), 0 }, + { INT_RANGE(go_interworking, 0, 1), 0 }, + { INT_RANGE(go_access_network_type, 0, 15), 0 }, + { INT_RANGE(go_internet, 0, 1), 0 }, + { INT_RANGE(go_venue_group, 0, 255), 0 }, + { INT_RANGE(go_venue_type, 0, 255), 0 }, { INT_RANGE(pbc_in_m1, 0, 1), 0 }, { STR(autoscan), 0 }, { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), @@ -4345,9 +4834,10 @@ static const struct global_parse_data global_fields[] = { { FUNC(freq_list), 0 }, { INT(scan_cur_freq), 0 }, { INT(sched_scan_interval), 0 }, + { INT(sched_scan_start_delay), 0 }, { INT(tdls_external_control), 0}, { STR(osu_dir), 0 }, - { STR(wowlan_triggers), 0 }, + { STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS }, { INT(p2p_search_delay), 0}, { INT(mac_addr), 0 }, { INT(rand_addr_lifetime), 0 }, @@ -4361,16 +4851,23 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 }, { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 }, #endif /* CONFIG_FST */ + { INT_RANGE(cert_in_cb, 0, 1), 0 }, { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 }, { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS }, #ifdef CONFIG_MBO { STR(non_pref_chan), 0 }, { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE, MBO_CELL_CAPA_NOT_SUPPORTED), 0 }, -#endif /*CONFIG_MBO */ + { INT_RANGE(disassoc_imminent_rssi_threshold, -120, 0), 0 }, + { INT_RANGE(oce, 0, 3), 0 }, +#endif /* CONFIG_MBO */ { INT(gas_address3), 0 }, { INT_RANGE(ftm_responder, 0, 1), 0 }, { INT_RANGE(ftm_initiator, 0, 1), 0 }, + { INT(gas_rand_addr_lifetime), 0 }, + { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 }, + { INT_RANGE(dpp_config_processing, 0, 2), 0 }, + { INT_RANGE(coloc_intf_reporting, 0, 1), 0 }, }; #undef FUNC diff --git a/contrib/wpa/wpa_supplicant/config.h b/contrib/wpa/wpa_supplicant/config.h index 48e64be5da1a..abbd8c90e2b5 100644 --- a/contrib/wpa/wpa_supplicant/config.h +++ b/contrib/wpa/wpa_supplicant/config.h @@ -32,6 +32,7 @@ #define DEFAULT_BSS_EXPIRATION_AGE 180 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2 #define DEFAULT_MAX_NUM_STA 128 +#define DEFAULT_AP_ISOLATE 0 #define DEFAULT_ACCESS_NETWORK_TYPE 15 #define DEFAULT_SCAN_CUR_FREQ 0 #define DEFAULT_P2P_SEARCH_DELAY 500 @@ -41,6 +42,8 @@ #define DEFAULT_P2P_GO_CTWINDOW 0 #define DEFAULT_WPA_RSC_RELAXATION 1 #define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED +#define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75 +#define DEFAULT_OCE_SUPPORT OCE_STA #include "config_ssid.h" #include "wps/wps.h" @@ -48,6 +51,9 @@ #include "common/ieee802_11_common.h" +#define MAX_ROAMING_CONS 36 +#define MAX_ROAMING_CONS_OI_LEN 15 + struct wpa_cred { /** * next - Next credential in the list @@ -222,10 +228,43 @@ struct wpa_cred { */ size_t roaming_consortium_len; + /** + * required_roaming_consortium - Required Roaming Consortium OI + * + * If required_roaming_consortium_len is non-zero, this field contains + * the Roaming Consortium OI that is required to be advertised by the AP + * for the credential to be considered matching. + */ u8 required_roaming_consortium[15]; + + /** + * required_roaming_consortium_len - Length of required_roaming_consortium + */ size_t required_roaming_consortium_len; /** + * roaming_consortiums - Roaming Consortium OI(s) memberships + * + * This field contains one or more OIs identifying the roaming + * consortiums of which the provider is a member. The list is sorted + * from the most preferred one to the least preferred one. A match + * between the Roaming Consortium OIs advertised by an AP and the OIs + * in this list indicates that successful authentication is possible. + * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI) + */ + u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; + + /** + * roaming_consortiums_len - Length on roaming_consortiums[i] + */ + size_t roaming_consortiums_len[MAX_ROAMING_CONS]; + + /** + * num_roaming_consortiums - Number of entries in roaming_consortiums + */ + unsigned int num_roaming_consortiums; + + /** * eap_method - EAP method to use * * Pre-configured EAP method to use with this credential or %NULL to @@ -334,6 +373,7 @@ struct wpa_cred { #define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15) #define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16) #define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17) +#define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18) /** * struct wpa_config - wpa_supplicant configuration data @@ -625,6 +665,13 @@ struct wpa_config { u8 uuid[16]; /** + * auto_uuid - Automatic UUID behavior + * 0 = generate static value based on the local MAC address (default) + * 1 = generate a random UUID every time wpa_supplicant starts + */ + int auto_uuid; + + /** * device_name - Device Name (WPS) * User-friendly description of device; up to 32 octets encoded in * UTF-8 @@ -698,6 +745,16 @@ struct wpa_config { */ int wps_cred_processing; + /** + * wps_cred_add_sae - Whether to enable SAE automatically for WPS + * + * 0 = only add the explicitly listed WPA2-PSK configuration + * 1 = add both the WPA2-PSK and SAE configuration and enable PMF so + * that the station gets configured in WPA3-Personal transition mode + * (supports both WPA2-Personal (PSK) and WPA3-Personal (SAE) APs). + */ + int wps_cred_add_sae; + #define MAX_SEC_DEVICE_TYPES 5 /** * sec_device_types - Secondary Device Types (P2P) @@ -833,6 +890,20 @@ struct wpa_config { unsigned int max_num_sta; /** + * ap_isolate - Whether to use client isolation feature + * + * Client isolation can be used to prevent low-level bridging of + * frames between associated stations in the BSS. By default, + * this bridging is allowed (ap_isolate=0); except in P2P GO case, + * where p2p_intra_bss parameter is used to determine whether to allow + * intra-BSS forwarding (ap_isolate = !p2p_intra_bss). + * + * 0 = do not enable AP isolation + * 1 = enable AP isolation + */ + int ap_isolate; + + /** * freq_list - Array of allowed scan frequencies or %NULL for all * * This is an optional zero-terminated array of frequencies in @@ -854,7 +925,7 @@ struct wpa_config { unsigned int changed_parameters; /** - * disassoc_low_ack - Disassocicate stations with massive packet loss + * disassoc_low_ack - Disassociate stations with massive packet loss */ int disassoc_low_ack; @@ -872,6 +943,34 @@ struct wpa_config { */ int access_network_type; + /** + * go_interworking - Whether Interworking for P2P GO is enabled + */ + int go_interworking; + + /** + * go_access_network_type - P2P GO Access Network Type + * + * This indicates which access network type to advertise if Interworking + * is enabled for P2P GO. + */ + int go_access_network_type; + + /** + * go_internet - Interworking: Internet connectivity (0 or 1) + */ + int go_internet; + + /** + * go_venue_group - Interworking: Venue group + */ + int go_venue_group; + + /** + * go_venue_type: Interworking: Venue type + */ + int go_venue_type; + /** * hessid - Homogenous ESS identifier * @@ -990,6 +1089,16 @@ struct wpa_config { int p2p_go_vht; /** + * p2p_go_he - Default mode for 11ax HE enable when operating as GO + * + * This will take effect for p2p_group_add, p2p_connect, and p2p_invite. + * Note that regulatory constraints and driver capabilities are + * consulted anyway, so setting it to 1 can't do real harm. + * By default: 0 (disabled) + */ + int p2p_go_he; + + /** * p2p_go_ctwindow - CTWindow to use when operating as GO * * By default: 0 (no CTWindow). Values 0-127 can be used to indicate @@ -1096,6 +1205,15 @@ struct wpa_config { unsigned int sched_scan_interval; /** + * sched_scan_start_delay - Schedule scan start delay before first scan + * + * Delay (in seconds) before scheduling first scan plan cycle. The + * driver may ignore this parameter and start immediately (or at any + * other time), if this feature is not supported. + */ + unsigned int sched_scan_start_delay; + + /** * tdls_external_control - External control for TDLS setup requests * * Enable TDLS mode where external programs are given the control @@ -1291,6 +1409,19 @@ struct wpa_config { * mbo_cell_capa - Cellular capabilities for MBO */ enum mbo_cellular_capa mbo_cell_capa; + + /** + * disassoc_imminent_rssi_threshold - RSSI threshold of candidate AP + * when disassociation imminent is set. + */ + int disassoc_imminent_rssi_threshold; + + /** + * oce - Enable OCE in STA and/or STA-CFON mode + * - Set BIT(0) to enable OCE in non-AP STA mode + * - Set BIT(1) to enable OCE in STA-CFON mode + */ + unsigned int oce; #endif /* CONFIG_MBO */ /** @@ -1328,6 +1459,74 @@ struct wpa_config { * wpa_supplicant. */ int ftm_initiator; + + /** + * gas_rand_addr_lifetime - Lifetime of random MAC address for ANQP in + * seconds + */ + unsigned int gas_rand_addr_lifetime; + + /** + * gas_rand_mac_addr - GAS MAC address policy + * + * 0 = use permanent MAC address + * 1 = use random MAC address + * 2 = like 1, but maintain OUI (with local admin bit set) + */ + int gas_rand_mac_addr; + + /** + * dpp_config_processing - How to process DPP configuration + * + * 0 = report received configuration to an external program for + * processing; do not generate any network profile internally + * 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 + */ + int dpp_config_processing; + + /** + * coloc_intf_reporting - Colocated interference reporting + * + * dot11CoLocIntfReportingActivated + * 0 = disabled (false) + * 1 = enabled (true) + */ + int coloc_intf_reporting; + + /** + * p2p_device_random_mac_addr - P2P Device MAC address policy default + * + * 0 = use permanent MAC address + * 1 = use random MAC address on creating the interface if there is no + * persistent groups. + * + * By default, permanent MAC address is used. + */ + int p2p_device_random_mac_addr; + + /** + * p2p_device_persistent_mac_addr - Record last used MAC address + * + * If there are saved persistent groups, P2P cannot generate another + * random MAC address, and need to restore to last used MAC address. + */ + u8 p2p_device_persistent_mac_addr[ETH_ALEN]; + + /** + * p2p_interface_random_mac_addr - P2P Interface MAC address policy default + * + * 0 = use permanent MAC address + * 1 = use random MAC address on creating the interface. + * + * By default, permanent MAC address is used. + */ + int p2p_interface_random_mac_addr; }; diff --git a/contrib/wpa/wpa_supplicant/config_file.c b/contrib/wpa/wpa_supplicant/config_file.c index 7ae16545bebc..26f6ee147844 100644 --- a/contrib/wpa/wpa_supplicant/config_file.c +++ b/contrib/wpa/wpa_supplicant/config_file.c @@ -19,6 +19,7 @@ #include "config.h" #include "base64.h" #include "uuid.h" +#include "common/ieee802_1x_defs.h" #include "p2p/p2p.h" #include "eap_peer/eap_methods.h" #include "eap_peer/eap.h" @@ -136,9 +137,13 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) wpa_config_update_psk(ssid); } + if (ssid->disabled == 2) + ssid->p2p_persistent_group = 1; + if ((ssid->group_cipher & WPA_CIPHER_CCMP) && - !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && - !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { + !(ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 | + WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256 | + WPA_CIPHER_NONE))) { /* Group cipher cannot be stronger than the pairwise cipher. */ wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher" " list since it was not allowed for pairwise " @@ -155,6 +160,15 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) errors++; } +#ifdef CONFIG_OCV + if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) { + wpa_printf(MSG_ERROR, + "Line %d: PMF needs to be enabled whenever using OCV", + line); + errors++; + } +#endif /* CONFIG_OCV */ + return errors; } @@ -308,7 +322,7 @@ static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line, encoded_len += len; } - if (!end) { + if (!end || !encoded) { wpa_printf(MSG_ERROR, "Line %d: blob was not terminated " "properly", *line); os_free(encoded); @@ -393,7 +407,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) if (f == NULL) { wpa_printf(MSG_ERROR, "Failed to open config file '%s', " "error: %s", name, strerror(errno)); - os_free(config); + if (config != cfgp) + os_free(config); return NULL; } @@ -459,7 +474,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) #ifndef WPA_IGNORE_CONFIG_ERRORS if (errors) { - wpa_config_free(config); + if (config != cfgp) + wpa_config_free(config); config = NULL; head = NULL; } @@ -477,7 +493,7 @@ static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid) if (value == NULL) return; fprintf(f, "\t%s=%s\n", field, value); - os_free(value); + str_clear_free(value); } @@ -499,6 +515,17 @@ static void write_bssid(FILE *f, struct wpa_ssid *ssid) } +static void write_bssid_hint(FILE *f, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "bssid_hint"); + + if (!value) + return; + fprintf(f, "\tbssid_hint=%s\n", value); + os_free(value); +} + + static void write_psk(FILE *f, struct wpa_ssid *ssid) { char *value; @@ -578,6 +605,22 @@ static void write_group(FILE *f, struct wpa_ssid *ssid) } +static void write_group_mgmt(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (!ssid->group_mgmt_cipher) + return; + + value = wpa_config_get(ssid, "group_mgmt"); + if (!value) + return; + if (value[0]) + fprintf(f, "\tgroup_mgmt=%s\n", value); + os_free(value); +} + + static void write_auth_alg(FILE *f, struct wpa_ssid *ssid) { char *value; @@ -662,6 +705,40 @@ static void write_psk_list(FILE *f, struct wpa_ssid *ssid) #endif /* CONFIG_P2P */ +#ifdef CONFIG_MACSEC + +static void write_mka_cak(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK)) + return; + + value = wpa_config_get(ssid, "mka_cak"); + if (!value) + return; + fprintf(f, "\tmka_cak=%s\n", value); + os_free(value); +} + + +static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN)) + return; + + value = wpa_config_get(ssid, "mka_ckn"); + if (!value) + return; + fprintf(f, "\tmka_ckn=%s\n", value); + os_free(value); +} + +#endif /* CONFIG_MACSEC */ + + static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) { int i; @@ -675,15 +752,19 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(ssid); INT(scan_ssid); write_bssid(f, ssid); + write_bssid_hint(f, ssid); write_str(f, "bssid_blacklist", ssid); write_str(f, "bssid_whitelist", ssid); write_psk(f, ssid); INT(mem_only_psk); + STR(sae_password); + STR(sae_password_id); write_proto(f, ssid); write_key_mgmt(f, ssid); INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD); write_pairwise(f, ssid); write_group(f, ssid); + write_group_mgmt(f, ssid); write_auth_alg(f, ssid); STR(bgscan); STR(autoscan); @@ -692,6 +773,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) write_eap(f, ssid); STR(identity); STR(anonymous_identity); + STR(imsi_identity); STR(password); STR(ca_cert); STR(ca_path); @@ -700,6 +782,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(private_key_passwd); STR(dh_file); STR(subject_match); + STR(check_cert_subject); STR(altsubject_match); STR(domain_suffix_match); STR(domain_match); @@ -710,6 +793,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(private_key2_passwd); STR(dh_file2); STR(subject_match2); + STR(check_cert_subject2); STR(altsubject_match2); STR(domain_suffix_match2); STR(domain_match2); @@ -752,11 +836,16 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) #endif /* CONFIG_ACS */ write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1); INT(disabled); - INT(peerkey); INT(mixed_cell); - INT(max_oper_chwidth); + INT(vht); + INT_DEF(ht, 1); + INT(ht40); + INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH); + INT(vht_center_freq1); + INT(vht_center_freq2); INT(pbss); INT(wps_disabled); + INT(fils_dh_group); #ifdef CONFIG_IEEE80211W write_int(f, "ieee80211w", ssid->ieee80211w, MGMT_FRAME_PROTECTION_DEFAULT); @@ -772,9 +861,17 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(beacon_int); #ifdef CONFIG_MACSEC INT(macsec_policy); + write_mka_cak(f, ssid); + write_mka_ckn(f, ssid); + INT(macsec_integ_only); + INT(macsec_replay_protect); + INT(macsec_replay_window); + INT(macsec_port); + INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER); #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 INT(update_identifier); + STR(roaming_consortium_selection); #endif /* CONFIG_HS20 */ write_int(f, "mac_addr", ssid->mac_addr, -1); #ifdef CONFIG_MESH @@ -783,16 +880,28 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT); INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT); INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT); + INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD); #endif /* CONFIG_MESH */ INT(wpa_ptk_rekey); INT(group_rekey); INT(ignore_broadcast_ssid); +#ifdef CONFIG_DPP + STR(dpp_connector); + STR(dpp_netaccesskey); + INT(dpp_netaccesskey_expiry); + STR(dpp_csign); +#endif /* CONFIG_DPP */ + INT(owe_group); + INT(owe_only); + INT(multi_ap_backhaul_sta); #ifdef CONFIG_HT_OVERRIDES INT_DEF(disable_ht, DEFAULT_DISABLE_HT); INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40); INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI); INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC); INT(ht40_intolerant); + INT_DEF(tx_stbc, DEFAULT_TX_STBC); + INT_DEF(rx_stbc, DEFAULT_RX_STBC); INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU); INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR); INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY); @@ -949,6 +1058,20 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) fprintf(f, "\n"); } + if (cred->num_roaming_consortiums) { + size_t j; + + fprintf(f, "\troaming_consortiums=\""); + for (i = 0; i < cred->num_roaming_consortiums; i++) { + if (i > 0) + fprintf(f, ","); + for (j = 0; j < cred->roaming_consortiums_len[i]; j++) + fprintf(f, "%02x", + cred->roaming_consortiums[i][j]); + } + fprintf(f, "\"\n"); + } + if (cred->sim_num != DEFAULT_USER_SELECTED_SIM) fprintf(f, "\tsim_num=%d\n", cred->sim_num); } @@ -1039,6 +1162,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) uuid_bin2str(config->uuid, buf, sizeof(buf)); fprintf(f, "uuid=%s\n", buf); } + if (config->auto_uuid) + fprintf(f, "auto_uuid=%d\n", config->auto_uuid); if (config->device_name) fprintf(f, "device_name=%s\n", config->device_name); if (config->manufacturer) @@ -1064,6 +1189,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->wps_cred_processing) fprintf(f, "wps_cred_processing=%d\n", config->wps_cred_processing); + if (config->wps_cred_add_sae) + fprintf(f, "wps_cred_add_sae=%d\n", + config->wps_cred_add_sae); if (config->wps_vendor_ext_m1) { int i, len = wpabuf_len(config->wps_vendor_ext_m1); const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1); @@ -1076,6 +1204,17 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P + { + int i; + char _buf[WPS_DEV_TYPE_BUFSIZE], *buf; + + for (i = 0; i < config->num_sec_device_types; i++) { + buf = wps_dev_type_bin2str(config->sec_device_type[i], + _buf, sizeof(_buf)); + if (buf) + fprintf(f, "sec_device_type=%s\n", buf); + } + } if (config->p2p_listen_reg_class) fprintf(f, "p2p_listen_reg_class=%d\n", config->p2p_listen_reg_class); @@ -1128,6 +1267,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "p2p_go_ht40=%d\n", config->p2p_go_ht40); if (config->p2p_go_vht) fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht); + if (config->p2p_go_he) + fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he); if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW) fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow); if (config->p2p_disabled) @@ -1175,8 +1316,12 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) config->bss_expiration_scan_count); if (config->filter_ssids) fprintf(f, "filter_ssids=%d\n", config->filter_ssids); + if (config->filter_rssi) + fprintf(f, "filter_rssi=%d\n", config->filter_rssi); if (config->max_num_sta != DEFAULT_MAX_NUM_STA) fprintf(f, "max_num_sta=%u\n", config->max_num_sta); + if (config->ap_isolate != DEFAULT_AP_ISOLATE) + fprintf(f, "ap_isolate=%u\n", config->ap_isolate); if (config->disassoc_low_ack) fprintf(f, "disassoc_low_ack=%d\n", config->disassoc_low_ack); #ifdef CONFIG_HS20 @@ -1191,6 +1336,17 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE) fprintf(f, "access_network_type=%d\n", config->access_network_type); + if (config->go_interworking) + fprintf(f, "go_interworking=%d\n", config->go_interworking); + if (config->go_access_network_type) + fprintf(f, "go_access_network_type=%d\n", + config->go_access_network_type); + if (config->go_internet) + fprintf(f, "go_internet=%d\n", config->go_internet); + if (config->go_venue_group) + fprintf(f, "go_venue_group=%d\n", config->go_venue_group); + if (config->go_venue_type) + fprintf(f, "go_venue_type=%d\n", config->go_venue_type); #endif /* CONFIG_INTERWORKING */ if (config->pbc_in_m1) fprintf(f, "pbc_in_m1=%d\n", config->pbc_in_m1); @@ -1226,7 +1382,7 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->sae_groups) { int i; fprintf(f, "sae_groups="); - for (i = 0; config->sae_groups[i] >= 0; i++) { + for (i = 0; config->sae_groups[i] > 0; i++) { fprintf(f, "%s%d", i > 0 ? " " : "", config->sae_groups[i]); } @@ -1264,6 +1420,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "sched_scan_interval=%u\n", config->sched_scan_interval); + if (config->sched_scan_start_delay) + fprintf(f, "sched_scan_start_delay=%u\n", + config->sched_scan_start_delay); + if (config->external_sim) fprintf(f, "external_sim=%d\n", config->external_sim); @@ -1278,6 +1438,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->bgscan) fprintf(f, "bgscan=\"%s\"\n", config->bgscan); + if (config->autoscan) + fprintf(f, "autoscan=%s\n", config->autoscan); + if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY) fprintf(f, "p2p_search_delay=%u\n", config->p2p_search_delay); @@ -1335,6 +1498,12 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "non_pref_chan=%s\n", config->non_pref_chan); if (config->mbo_cell_capa != DEFAULT_MBO_CELL_CAPA) fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa); + if (config->disassoc_imminent_rssi_threshold != + DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD) + fprintf(f, "disassoc_imminent_rssi_threshold=%d\n", + config->disassoc_imminent_rssi_threshold); + if (config->oce != DEFAULT_OCE_SUPPORT) + fprintf(f, "oce=%u\n", config->oce); #endif /* CONFIG_MBO */ if (config->gas_address3) @@ -1344,6 +1513,37 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "ftm_responder=%d\n", config->ftm_responder); if (config->ftm_initiator) fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator); + + if (config->osu_dir) + fprintf(f, "osu_dir=%s\n", config->osu_dir); + + if (config->fst_group_id) + fprintf(f, "fst_group_id=%s\n", config->fst_group_id); + if (config->fst_priority) + fprintf(f, "fst_priority=%d\n", config->fst_priority); + if (config->fst_llt) + fprintf(f, "fst_llt=%d\n", config->fst_llt); + + if (config->gas_rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME) + fprintf(f, "gas_rand_addr_lifetime=%u\n", + config->gas_rand_addr_lifetime); + if (config->gas_rand_mac_addr) + fprintf(f, "gas_rand_mac_addr=%d\n", config->gas_rand_mac_addr); + if (config->dpp_config_processing) + fprintf(f, "dpp_config_processing=%d\n", + config->dpp_config_processing); + if (config->coloc_intf_reporting) + fprintf(f, "coloc_intf_reporting=%d\n", + config->coloc_intf_reporting); + if (config->p2p_device_random_mac_addr) + fprintf(f, "p2p_device_random_mac_addr=%d\n", + config->p2p_device_random_mac_addr); + if (!is_zero_ether_addr(config->p2p_device_persistent_mac_addr)) + fprintf(f, "p2p_device_persistent_mac_addr=" MACSTR "\n", + MAC2STR(config->p2p_device_persistent_mac_addr)); + if (config->p2p_interface_random_mac_addr) + fprintf(f, "p2p_interface_random_mac_addr=%d\n", + config->p2p_interface_random_mac_addr); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/contrib/wpa/wpa_supplicant/config_ssid.h b/contrib/wpa/wpa_supplicant/config_ssid.h index 010b594af85e..1b2b1f1a36f1 100644 --- a/contrib/wpa/wpa_supplicant/config_ssid.h +++ b/contrib/wpa/wpa_supplicant/config_ssid.h @@ -28,14 +28,18 @@ #define DEFAULT_MESH_RETRY_TIMEOUT 40 #define DEFAULT_MESH_CONFIRM_TIMEOUT 40 #define DEFAULT_MESH_HOLDING_TIMEOUT 40 +#define DEFAULT_MESH_RSSI_THRESHOLD 1 /* no change */ #define DEFAULT_DISABLE_HT 0 #define DEFAULT_DISABLE_HT40 0 #define DEFAULT_DISABLE_SGI 0 #define DEFAULT_DISABLE_LDPC 0 +#define DEFAULT_TX_STBC -1 /* no change */ +#define DEFAULT_RX_STBC -1 /* no change */ #define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */ #define DEFAULT_AMPDU_FACTOR -1 /* no change */ #define DEFAULT_AMPDU_DENSITY -1 /* no change */ #define DEFAULT_USER_SELECTED_SIM 1 +#define DEFAULT_MAX_OPER_CHWIDTH -1 struct psk_list_entry { struct dl_list list; @@ -146,6 +150,19 @@ struct wpa_ssid { int bssid_set; /** + * bssid_hint - BSSID hint + * + * If set, this is configured to the driver as a preferred initial BSSID + * while connecting to this network. + */ + u8 bssid_hint[ETH_ALEN]; + + /** + * bssid_hint_set - Whether BSSID hint is configured for this network + */ + int bssid_hint_set; + + /** * go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set */ u8 go_p2p_dev_addr[ETH_ALEN]; @@ -170,6 +187,24 @@ struct wpa_ssid { char *passphrase; /** + * sae_password - SAE password + * + * This parameter can be used to set a password for SAE. By default, the + * passphrase value is used if this separate parameter is not used, but + * passphrase follows the WPA-PSK constraints (8..63 characters) even + * though SAE passwords do not have such constraints. + */ + char *sae_password; + + /** + * sae_password_id - SAE password identifier + * + * This parameter can be used to identify a specific SAE password. If + * not included, the default SAE password is used instead. + */ + char *sae_password_id; + + /** * ext_psk - PSK/passphrase name in external storage * * If this is set, PSK/passphrase will be fetched from external storage @@ -196,6 +231,15 @@ struct wpa_ssid { int group_cipher; /** + * group_mgmt_cipher - Bitfield of allowed group management ciphers + * + * This is a bitfield of WPA_CIPHER_AES_128_CMAC and WPA_CIPHER_BIP_* + * values. If 0, no constraint is used for the cipher, i.e., whatever + * the AP uses is accepted. + */ + int group_mgmt_cipher; + + /** * key_mgmt - Bitfield of allowed key management protocols * * WPA_KEY_MGMT_* @@ -392,17 +436,6 @@ struct wpa_ssid { int disabled_for_connect; /** - * peerkey - Whether PeerKey handshake for direct links is allowed - * - * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are - * enabled. - * - * 0 = disabled (default) - * 1 = enabled - */ - int peerkey; - - /** * id_str - Network identifier string for external scripts * * This value is passed to external ctrl_iface monitors in @@ -427,6 +460,17 @@ struct wpa_ssid { enum mfp_options ieee80211w; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + /** + * ocv - Enable/disable operating channel validation + * + * If this parameter is set to 1, stations will exchange OCI element + * to cryptographically verify the operating channel. Setting this + * parameter to 0 disables this option. Default value: 0. + */ + int ocv; +#endif /* CONFIG_OCV */ + /** * frequency - Channel frequency in megahertz (MHz) for IBSS * @@ -470,12 +514,16 @@ struct wpa_ssid { int dot11MeshConfirmTimeout; /* msec */ int dot11MeshHoldingTimeout; /* msec */ + int ht; int ht40; int vht; - u8 max_oper_chwidth; + int he; + int max_oper_chwidth; + + unsigned int vht_center_freq1; unsigned int vht_center_freq2; /** @@ -650,6 +698,22 @@ struct wpa_ssid { * By default (empty string): Use whatever the OS has configured. */ char *ht_mcs; + + /** + * tx_stbc - Indicate STBC support for TX streams + * + * Value: -1..1, by default (-1): use whatever the OS or card has + * configured. See IEEE Std 802.11-2016, 9.4.2.56.2. + */ + int tx_stbc; + + /** + * rx_stbc - Indicate STBC support for RX streams + * + * Value: -1..3, by default (-1): use whatever the OS or card has + * configured. See IEEE Std 802.11-2016, 9.4.2.56.2. + */ + int rx_stbc; #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES @@ -728,10 +792,100 @@ struct wpa_ssid { * 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 */ #ifdef CONFIG_HS20 int update_identifier; + + /** + * roaming_consortium_selection - Roaming Consortium Selection + * + * The matching Roaming Consortium OI that was used to generate this + * network profile. + */ + u8 *roaming_consortium_selection; + + /** + * roaming_consortium_selection_len - roaming_consortium_selection len + */ + size_t roaming_consortium_selection_len; #endif /* CONFIG_HS20 */ unsigned int wps_run; @@ -758,12 +912,99 @@ struct wpa_ssid { int no_auto_peer; /** + * mesh_rssi_threshold - Set mesh parameter mesh_rssi_threshold (dBm) + * + * -255..-1 = threshold value in dBm + * 0 = not using RSSI threshold + * 1 = do not change driver default + */ + int mesh_rssi_threshold; + + /** * wps_disabled - WPS disabled in AP mode * * 0 = WPS enabled and configured (default) * 1 = WPS disabled */ int wps_disabled; + + /** + * fils_dh_group - FILS DH Group + * + * 0 = PFS disabled with FILS shared key authentication + * 1-65535 DH Group to use for FILS PFS + */ + int fils_dh_group; + + /** + * dpp_connector - DPP Connector (signedConnector as string) + */ + char *dpp_connector; + + /** + * dpp_netaccesskey - DPP netAccessKey (own private key) + */ + u8 *dpp_netaccesskey; + + /** + * dpp_netaccesskey_len - DPP netAccessKey length in octets + */ + size_t dpp_netaccesskey_len; + + /** + * net_access_key_expiry - DPP netAccessKey expiry in UNIX time stamp + * + * 0 indicates no expiration. + */ + unsigned int dpp_netaccesskey_expiry; + + /** + * dpp_csign - C-sign-key (Configurator public key) + */ + u8 *dpp_csign; + + /** + * dpp_csign_len - C-sign-key length in octets + */ + size_t dpp_csign_len; + + /** + * owe_group - OWE DH Group + * + * 0 = use default (19) first and then try all supported groups one by + * one if AP rejects the selected group + * 1-65535 DH Group to use for OWE + * + * Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are + * currently supported. + */ + int owe_group; + + /** + * owe_only - OWE-only mode (disable transition mode) + * + * 0 = enable transition mode (allow connection to either OWE or open + * BSS) + * 1 = disable transition mode (allow connection only with OWE) + */ + int owe_only; + + /** + * owe_transition_bss_select_count - OWE transition BSS select count + * + * This is an internally used variable (i.e., not used in external + * configuration) to track the number of selection attempts done for + * OWE BSS in transition mode. This allows fallback to an open BSS if + * the selection attempts for OWE BSS exceed the configured threshold. + */ + int owe_transition_bss_select_count; + + /** + * multi_ap_backhaul_sta - Multi-AP backhaul STA + * 0 = normal (non-Multi-AP) station + * 1 = Multi-AP backhaul station + */ + int multi_ap_backhaul_sta; }; #endif /* CONFIG_SSID_H */ diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.c b/contrib/wpa/wpa_supplicant/ctrl_iface.c index d814fdf7fd2d..198ac562d8b6 100644 --- a/contrib/wpa/wpa_supplicant/ctrl_iface.c +++ b/contrib/wpa/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,9 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" +#ifdef CONFIG_DPP +#include "common/dpp.h" +#endif /* CONFIG_DPP */ #include "crypto/tls.h" #include "ap/hostapd.h" #include "eap_peer/eap.h" @@ -52,6 +55,8 @@ #include "offchannel.h" #include "drivers/driver.h" #include "mesh.h" +#include "dpp_supplicant.h" +#include "sme.h" static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); @@ -61,6 +66,7 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val); + static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) { char *pos; @@ -339,6 +345,75 @@ static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, } +static int +wpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int relative_rssi; + + if (os_strcmp(cmd, "disable") == 0) { + wpa_s->srp.relative_rssi_set = 0; + return 0; + } + + relative_rssi = atoi(cmd); + if (relative_rssi < 0 || relative_rssi > 100) + return -1; + wpa_s->srp.relative_rssi = relative_rssi; + wpa_s->srp.relative_rssi_set = 1; + return 0; +} + + +static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + char *pos; + int adjust_rssi; + + /* <band>:adjust_value */ + pos = os_strchr(cmd, ':'); + if (!pos) + return -1; + pos++; + adjust_rssi = atoi(pos); + if (adjust_rssi < -100 || adjust_rssi > 100) + return -1; + + if (os_strncmp(cmd, "2G", 2) == 0) + wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G; + else if (os_strncmp(cmd, "5G", 2) == 0) + wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G; + else + return -1; + + wpa_s->srp.relative_adjust_rssi = adjust_rssi; + + return 0; +} + + +static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *ric_ies; + + if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) { + wpabuf_free(wpa_s->ric_ies); + wpa_s->ric_ies = NULL; + return 0; + } + + ric_ies = wpabuf_parse_bin(cmd); + if (!ric_ies) + return -1; + + wpabuf_free(wpa_s->ric_ies); + wpa_s->ric_ies = ric_ies; + + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -365,16 +440,29 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, -1, -1, -1, atoi(value)); } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, - atoi(value))) + atoi(value))) { ret = -1; + } else { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, - atoi(value))) + atoi(value))) { ret = -1; + } else { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { - if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) + if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, + atoi(value))) { ret = -1; + } else { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { wpa_s->wps_fragment_size = atoi(value); #ifdef CONFIG_WPS_TESTING @@ -494,6 +582,59 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, ret = set_disallow_aps(wpa_s, value); } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) { wpa_s->no_keep_alive = !!atoi(value); +#ifdef CONFIG_DPP + } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { + os_free(wpa_s->dpp_configurator_params); + wpa_s->dpp_configurator_params = os_strdup(value); + } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { + wpa_s->dpp_init_max_tries = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { + wpa_s->dpp_init_retry_time = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) { + wpa_s->dpp_resp_wait_time = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) { + wpa_s->dpp_resp_max_tries = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) { + wpa_s->dpp_resp_retry_time = atoi(value); +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcasecmp(cmd, "dpp_pkex_own_mac_override") == 0) { + if (hwaddr_aton(value, dpp_pkex_own_mac_override)) + ret = -1; + } else if (os_strcasecmp(cmd, "dpp_pkex_peer_mac_override") == 0) { + if (hwaddr_aton(value, dpp_pkex_peer_mac_override)) + ret = -1; + } else if (os_strcasecmp(cmd, "dpp_pkex_ephemeral_key_override") == 0) { + size_t hex_len = os_strlen(value); + + if (hex_len > + 2 * sizeof(dpp_pkex_ephemeral_key_override)) + ret = -1; + else if (hexstr2bin(value, dpp_pkex_ephemeral_key_override, + hex_len / 2)) + ret = -1; + else + dpp_pkex_ephemeral_key_override_len = hex_len / 2; + } else if (os_strcasecmp(cmd, "dpp_protocol_key_override") == 0) { + size_t hex_len = os_strlen(value); + + if (hex_len > 2 * sizeof(dpp_protocol_key_override)) + ret = -1; + else if (hexstr2bin(value, dpp_protocol_key_override, + hex_len / 2)) + ret = -1; + else + dpp_protocol_key_override_len = hex_len / 2; + } else if (os_strcasecmp(cmd, "dpp_nonce_override") == 0) { + size_t hex_len = os_strlen(value); + + if (hex_len > 2 * sizeof(dpp_nonce_override)) + ret = -1; + else if (hexstr2bin(value, dpp_nonce_override, hex_len / 2)) + ret = -1; + else + dpp_nonce_override_len = hex_len / 2; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_DPP */ #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { wpa_s->ext_mgmt_frame_handling = !!atoi(value); @@ -515,9 +656,54 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->ignore_auth_resp = !!atoi(value); } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) { wpa_s->ignore_assoc_disallow = !!atoi(value); + wpa_drv_ignore_assoc_disallow(wpa_s, + wpa_s->ignore_assoc_disallow); } 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) { + os_free(wpa_s->get_pref_freq_list_override); + if (!value[0]) + wpa_s->get_pref_freq_list_override = NULL; + else + wpa_s->get_pref_freq_list_override = os_strdup(value); + } else if (os_strcasecmp(cmd, "sae_commit_override") == 0) { + wpabuf_free(wpa_s->sae_commit_override); + if (value[0] == '\0') + wpa_s->sae_commit_override = NULL; + else + wpa_s->sae_commit_override = wpabuf_parse_bin(value); +#ifdef CONFIG_DPP + } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { + os_free(wpa_s->dpp_config_obj_override); + if (value[0] == '\0') + wpa_s->dpp_config_obj_override = NULL; + else + wpa_s->dpp_config_obj_override = os_strdup(value); + } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) { + os_free(wpa_s->dpp_discovery_override); + if (value[0] == '\0') + wpa_s->dpp_discovery_override = NULL; + else + wpa_s->dpp_discovery_override = os_strdup(value); + } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) { + os_free(wpa_s->dpp_groups_override); + if (value[0] == '\0') + wpa_s->dpp_groups_override = NULL; + else + wpa_s->dpp_groups_override = os_strdup(value); + } else if (os_strcasecmp(cmd, + "dpp_ignore_netaccesskey_mismatch") == 0) { + wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_test") == 0) { + dpp_test = atoi(value); +#endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_FILS + } else if (os_strcasecmp(cmd, "disable_fils") == 0) { + wpa_s->disable_fils = !!atoi(value); + wpa_drv_disable_fils(wpa_s, wpa_s->disable_fils); + wpa_supplicant_set_default_scan_ies(wpa_s); +#endif /* CONFIG_FILS */ #ifndef CONFIG_NO_CONFIG_BLOBS } else if (os_strcmp(cmd, "blob") == 0) { ret = wpas_ctrl_set_blob(wpa_s, value); @@ -527,11 +713,53 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) { ret = wpas_mbo_update_non_pref_chan(wpa_s, value); + if (ret == 0) { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { wpas_mbo_update_cell_capa(wpa_s, atoi(value)); + } else if (os_strcasecmp(cmd, "oce") == 0) { + wpa_s->conf->oce = atoi(value); + if (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; + + if ((wpa_s->conf->oce & OCE_STA_CFON) && + (wpa_s->drv_flags & + WPA_DRIVER_FLAGS_OCE_STA_CFON)) { + /* TODO: Need to add STA-CFON support */ + wpa_printf(MSG_ERROR, + "OCE STA-CFON feature is not yet supported"); + return -1; + } + } else { + wpa_s->enable_oce = 0; + } + wpa_supplicant_set_default_scan_ies(wpa_s); #endif /* CONFIG_MBO */ } else if (os_strcasecmp(cmd, "lci") == 0) { ret = wpas_ctrl_iface_set_lci(wpa_s, value); + } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) { + ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value)); + } else if (os_strcasecmp(cmd, "relative_rssi") == 0) { + ret = wpas_ctrl_set_relative_rssi(wpa_s, value); + } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) { + ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value); + } else if (os_strcasecmp(cmd, "ric_ies") == 0) { + ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value); + } else if (os_strcasecmp(cmd, "roaming") == 0) { + ret = wpa_drv_roaming(wpa_s, atoi(value), NULL); +#ifdef CONFIG_WNM + } else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) { + struct wpabuf *elems; + + elems = wpabuf_parse_bin(value); + if (!elems) + return -1; + wnm_set_coloc_intf_elems(wpa_s, elems); +#endif /* CONFIG_WNM */ } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -577,6 +805,12 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, #endif /* CONFIG_TESTING_GET_GTK */ } else if (os_strcmp(cmd, "tls_library") == 0) { res = tls_get_library_version(buf, buflen); +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcmp(cmd, "anonce") == 0) { + return wpa_snprintf_hex(buf, buflen, + wpa_sm_get_anonce(wpa_s->wpa), + WPA_NONCE_LEN); +#endif /* CONFIG_TESTING_OPTIONS */ } else { res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen); } @@ -610,27 +844,6 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s, #endif /* IEEE8021X_EAPOL */ -#ifdef CONFIG_PEERKEY -/* MLME-STKSTART.request(peer) */ -static int wpa_supplicant_ctrl_iface_stkstart( - struct wpa_supplicant *wpa_s, char *addr) -{ - u8 peer[ETH_ALEN]; - - if (hwaddr_aton(addr, peer)) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid " - "address '%s'", addr); - return -1; - } - - wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR, - MAC2STR(peer)); - - return wpa_sm_stkstart(wpa_s->wpa, peer); -} -#endif /* CONFIG_PEERKEY */ - - #ifdef CONFIG_TDLS static int wpa_supplicant_ctrl_iface_tdls_discover( @@ -955,8 +1168,11 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, #ifdef CONFIG_AP u8 *_p2p_dev_addr = NULL; #endif /* CONFIG_AP */ + char *pos; + int multi_ap = 0; - if (cmd == NULL || os_strcmp(cmd, "any") == 0) { + if (!cmd || os_strcmp(cmd, "any") == 0 || + os_strncmp(cmd, "any ", 4) == 0) { _bssid = NULL; #ifdef CONFIG_P2P } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { @@ -968,18 +1184,29 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, } _p2p_dev_addr = p2p_dev_addr; #endif /* CONFIG_P2P */ + } else if (os_strncmp(cmd, "multi_ap=", 9) == 0) { + _bssid = NULL; + multi_ap = atoi(cmd + 9); } else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", cmd); return -1; } + if (cmd) { + pos = os_strstr(cmd, " multi_ap="); + if (pos) { + pos += 10; + multi_ap = atoi(pos); + } + } + #ifdef CONFIG_AP if (wpa_s->ap_iface) return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr); #endif /* CONFIG_AP */ - return wpas_wps_start_pbc(wpa_s, _bssid, 0); + return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap); } @@ -1905,6 +2132,18 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += ret; } + if (wpa_s->connection_set && + (wpa_s->connection_ht || wpa_s->connection_vht || + wpa_s->connection_he)) { + ret = os_snprintf(pos, end - pos, + "wifi_generation=%u\n", + wpa_s->connection_he ? 6 : + (wpa_s->connection_vht ? 5 : 4)); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + #ifdef CONFIG_AP if (wpa_s->ap_iface) { pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos, @@ -1914,6 +2153,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, #endif /* CONFIG_AP */ pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); } +#ifdef CONFIG_SME #ifdef CONFIG_SAE if (wpa_s->wpa_state >= WPA_ASSOCIATED && #ifdef CONFIG_AP @@ -1927,6 +2167,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += ret; } #endif /* CONFIG_SAE */ +#endif /* CONFIG_SME */ ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", wpa_supplicant_state_txt(wpa_s->wpa_state)); if (os_snprintf_error(end - pos, ret)) @@ -2048,6 +2289,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += res; } +#ifdef CONFIG_MACSEC + res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos); + if (res > 0) + pos += res; +#endif /* CONFIG_MACSEC */ + sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len); if (sess_id) { char *start = pos; @@ -2081,6 +2328,13 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_WPS */ + if (wpa_s->ieee80211ac) { + ret = os_snprintf(pos, end - pos, "ieee80211ac=1\n"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + #ifdef ANDROID /* * Allow using the STATUS command with default behavior, say for debug, @@ -2437,6 +2691,59 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, } #endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_FILS + if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, "%sFILS-SHA256", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } + if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFILS-SHA384", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#ifdef CONFIG_IEEE80211R + if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } + if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_FILS */ + +#ifdef CONFIG_OWE + if (data.key_mgmt & WPA_KEY_MGMT_OWE) { + ret = os_snprintf(pos, end - pos, "%sOWE", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#endif /* CONFIG_OWE */ + +#ifdef CONFIG_DPP + if (data.key_mgmt & WPA_KEY_MGMT_DPP) { + ret = os_snprintf(pos, end - pos, "%sDPP", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#endif /* CONFIG_DPP */ + if (data.key_mgmt & WPA_KEY_MGMT_OSEN) { ret = os_snprintf(pos, end - pos, "%sOSEN", pos == start ? "" : "+"); @@ -2512,7 +2819,7 @@ static int wpa_supplicant_ctrl_iface_scan_result( { char *pos, *end; int ret; - const u8 *ie, *ie2, *osen_ie, *p2p, *mesh; + const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe; mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); @@ -2543,6 +2850,14 @@ static int wpa_supplicant_ctrl_iface_scan_result( if (osen_ie) pos = wpa_supplicant_ie_txt(pos, end, "OSEN", osen_ie, 2 + osen_ie[1]); + owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); + if (owe) { + ret = os_snprintf(pos, end - pos, + ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) { ret = os_snprintf(pos, end - pos, "[WEP]"); @@ -2608,6 +2923,14 @@ static int wpa_supplicant_ctrl_iface_scan_result( pos += ret; } #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FILS + if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) { + ret = os_snprintf(pos, end - pos, "[FILS]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } +#endif /* CONFIG_FILS */ #ifdef CONFIG_FST if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) { ret = os_snprintf(pos, end - pos, "[FST]"); @@ -2616,6 +2939,12 @@ static int wpa_supplicant_ctrl_iface_scan_result( pos += ret; } #endif /* CONFIG_FST */ + if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) { + ret = os_snprintf(pos, end - pos, "[UTF-8]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } ret = os_snprintf(pos, end - pos, "\t%s", wpa_ssid_txt(bss->ssid, bss->ssid_len)); @@ -2835,9 +3164,8 @@ static int wpa_supplicant_ctrl_iface_select_network( if (pos) { int *freqs = freq_range_to_channel_list(wpa_s, pos + 6); if (freqs) { - wpa_s->scan_req = MANUAL_SCAN_REQ; - os_free(wpa_s->manual_scan_freqs); - wpa_s->manual_scan_freqs = freqs; + os_free(wpa_s->select_network_scan_freqs); + wpa_s->select_network_scan_freqs = freqs; } } @@ -3012,6 +3340,7 @@ static int wpa_supplicant_ctrl_iface_update_network( return 0; /* No change to the previously configured value */ if (os_strcmp(name, "bssid") != 0 && + os_strcmp(name, "bssid_hint") != 0 && os_strcmp(name, "priority") != 0) { wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); @@ -3647,6 +3976,66 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict, pos += ret; } #endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_OWE + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) { + ret = os_snprintf(pos, end - pos, " OWE"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_OWE */ +#ifdef CONFIG_DPP + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) { + ret = os_snprintf(pos, end - pos, " DPP"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_DPP */ +#ifdef CONFIG_FILS + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, " FILS-SHA256"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, " FILS-SHA384"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#ifdef CONFIG_IEEE80211R + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211R + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) { + ret = os_snprintf(pos, end - pos, " FT-PSK"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SAE + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) { + ret = os_snprintf(pos, end - pos, " SAE"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SAE */ return pos - buf; } @@ -3749,6 +4138,26 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + if (wpa_is_fils_supported(wpa_s)) { + ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITHOUT_PFS", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + +#ifdef CONFIG_FILS_SK_PFS + if (wpa_is_fils_sk_pfs_supported(wpa_s)) { + ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITH_PFS", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_FILS_SK_PFS */ +#endif /* CONFIG_FILS */ + return pos - buf; } @@ -4006,6 +4415,47 @@ static int wpa_supplicant_ctrl_iface_get_capability( } #endif /* CONFIG_ACS */ +#ifdef CONFIG_FILS + if (os_strcmp(field, "fils") == 0) { +#ifdef CONFIG_FILS_SK_PFS + if (wpa_is_fils_supported(wpa_s) && + wpa_is_fils_sk_pfs_supported(wpa_s)) { + res = os_snprintf(buf, buflen, "FILS FILS-SK-PFS"); + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } +#endif /* CONFIG_FILS_SK_PFS */ + + if (wpa_is_fils_supported(wpa_s)) { + res = os_snprintf(buf, buflen, "FILS"); + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } + } +#endif /* CONFIG_FILS */ + + if (os_strcmp(field, "multibss") == 0 && wpa_s->multi_bss_support) { + res = os_snprintf(buf, buflen, "MULTIBSS-STA"); + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } + +#ifdef CONFIG_DPP + if (os_strcmp(field, "dpp") == 0) { +#ifdef CONFIG_DPP2 + res = os_snprintf(buf, buflen, "DPP=2"); +#else /* CONFIG_DPP2 */ + res = os_snprintf(buf, buflen, "DPP=1"); +#endif /* CONFIG_DPP2 */ + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } +#endif /* CONFIG_DPP */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", field); @@ -4048,13 +4498,85 @@ static char * anqp_add_hex(char *pos, char *end, const char *title, #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_FILS +static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) +{ + char *start = pos; + const u8 *ie, *ie_end; + u16 info, realms; + int ret; + + ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); + if (!ie) + return 0; + ie_end = ie + 2 + ie[1]; + ie += 2; + if (ie_end - ie < 2) + return -1; + + info = WPA_GET_LE16(ie); + ie += 2; + ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + if (info & BIT(7)) { + /* Cache Identifier Included */ + if (ie_end - ie < 2) + return -1; + ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n", + ie[0], ie[1]); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += 2; + } + + if (info & BIT(8)) { + /* HESSID Included */ + if (ie_end - ie < ETH_ALEN) + return -1; + ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n", + MAC2STR(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += ETH_ALEN; + } + + realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3; + if (realms) { + if (ie_end - ie < realms * 2) + return -1; + ret = os_snprintf(pos, end - pos, "fils_realms="); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2); + if (ret <= 0) + return 0; + pos += ret; + ie += realms * 2; + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + return pos - start; +} +#endif /* CONFIG_FILS */ + + static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, unsigned long mask, char *buf, size_t buflen) { size_t i; int ret; char *pos, *end; - const u8 *ie, *ie2, *osen_ie; + const u8 *ie, *ie2, *osen_ie, *mesh, *owe; pos = buf; end = buf + buflen; @@ -4163,18 +4685,30 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, return 0; pos += ret; + mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); + ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie) pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie2) - pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, + pos = wpa_supplicant_ie_txt(pos, end, + mesh ? "RSN" : "WPA2", ie2, 2 + ie2[1]); osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); if (osen_ie) pos = wpa_supplicant_ie_txt(pos, end, "OSEN", osen_ie, 2 + osen_ie[1]); + owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); + if (owe) { + ret = os_snprintf( + pos, end - pos, + ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) { @@ -4183,6 +4717,14 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, return 0; pos += ret; } + + if (mesh) { + ret = os_snprintf(pos, end - pos, "[MESH]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + if (bss_is_dmg(bss)) { const char *s; ret = os_snprintf(pos, end - pos, "[DMG]"); @@ -4236,6 +4778,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += ret; } #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FILS + if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) { + ret = os_snprintf(pos, end - pos, "[FILS]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } +#endif /* CONFIG_FILS */ +#ifdef CONFIG_FST + if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) { + ret = os_snprintf(pos, end - pos, "[FST]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } +#endif /* CONFIG_FST */ + if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) { + ret = os_snprintf(pos, end - pos, "[UTF-8]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } ret = os_snprintf(pos, end - pos, "\n"); if (os_snprintf_error(end - pos, ret)) @@ -4320,6 +4884,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp); pos = anqp_add_hex(pos, end, "anqp_domain_name", anqp->domain_name); + pos = anqp_add_hex(pos, end, "anqp_fils_realm_info", + anqp->fils_realm_info); #ifdef CONFIG_HS20 pos = anqp_add_hex(pos, end, "hs20_capability_list", anqp->hs20_capability_list); @@ -4333,6 +4899,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, anqp->hs20_operating_class); pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", anqp->hs20_osu_providers_list); + pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata", + anqp->hs20_operator_icon_metadata); + pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list", + anqp->hs20_osu_providers_nai_list); #endif /* CONFIG_HS20 */ dl_list_for_each(elem, &anqp->anqp_elems, @@ -4381,6 +4951,44 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } #endif /* CONFIG_FST */ + if (mask & WPA_BSS_MASK_UPDATE_IDX) { + ret = os_snprintf(pos, end - pos, "update_idx=%u\n", + bss->last_update_idx); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) { + ret = os_snprintf(pos, end - pos, "beacon_ie="); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ie = (const u8 *) (bss + 1); + ie += bss->ie_len; + for (i = 0; i < bss->beacon_ie_len; i++) { + ret = os_snprintf(pos, end - pos, "%02x", *ie++); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + +#ifdef CONFIG_FILS + if (mask & WPA_BSS_MASK_FILS_INDICATION) { + ret = print_fils_indication(bss, pos, end); + if (ret < 0) + return 0; + pos += ret; + } +#endif /* CONFIG_FILS */ + if (mask & WPA_BSS_MASK_DELIM) { ret = os_snprintf(pos, end - pos, "====\n"); if (os_snprintf_error(end - pos, ret)) @@ -4471,6 +5079,8 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, bss = dl_list_entry(next, struct wpa_bss, list_id); } + } else if (os_strncmp(cmd, "CURRENT", 7) == 0) { + bss = wpa_s->current_bss; #ifdef CONFIG_P2P } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { if (hwaddr_aton(cmd + 13, bssid) == 0) @@ -4486,10 +5096,11 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, bss = NULL; dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id) { - if (i-- == 0) { + if (i == 0) { bss = tmp; break; } + i--; } } @@ -4975,6 +5586,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL; size_t group_ssid_len = 0; + int he; if (!wpa_s->global->p2p_init_wpa_s) return -1; @@ -4987,7 +5599,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] * [persistent|persistent=<network id>] * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] - * [ht40] [vht] [auto] [ssid=<hexdump>] */ + * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */ if (hwaddr_aton(cmd, addr)) return -1; @@ -5018,6 +5630,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; + he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he; pos2 = os_strstr(pos, " go_intent="); if (pos2) { @@ -5088,7 +5701,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, automatic, join, auth, go_intent, freq, freq2, persistent_id, - pd, ht40, vht, max_oper_chwidth, + pd, ht40, vht, max_oper_chwidth, he, group_ssid, group_ssid_len); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); @@ -5644,7 +6257,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) struct wpa_ssid *ssid; u8 *_peer = NULL, peer[ETH_ALEN]; int freq = 0, pref_freq = 0; - int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; + int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0; id = atoi(cmd); pos = os_strstr(cmd, " peer="); @@ -5681,6 +6294,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; + he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he; pos = os_strstr(cmd, "freq2="); if (pos) @@ -5695,7 +6309,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) return -1; return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, - max_oper_chwidth, pref_freq); + max_oper_chwidth, pref_freq, he); } @@ -5743,7 +6357,8 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, int id, int freq, int vht_center_freq2, - int ht40, int vht, int vht_chwidth) + int ht40, int vht, int vht_chwidth, + int he) { struct wpa_ssid *ssid; @@ -5757,7 +6372,7 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, vht_center_freq2, 0, ht40, vht, - vht_chwidth, NULL, 0, 0); + vht_chwidth, he, NULL, 0, 0); } @@ -5766,20 +6381,31 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) int freq = 0, persistent = 0, group_id = -1; int vht = wpa_s->conf->p2p_go_vht; int ht40 = wpa_s->conf->p2p_go_ht40 || vht; + int he = wpa_s->conf->p2p_go_he; int max_oper_chwidth, chwidth = 0, freq2 = 0; char *token, *context = NULL; +#ifdef CONFIG_ACS + int acs = 0; +#endif /* CONFIG_ACS */ while ((token = str_token(cmd, " ", &context))) { - if (sscanf(token, "freq=%d", &freq) == 1 || - sscanf(token, "freq2=%d", &freq2) == 1 || + if (sscanf(token, "freq2=%d", &freq2) == 1 || sscanf(token, "persistent=%d", &group_id) == 1 || sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) { continue; +#ifdef CONFIG_ACS + } else if (os_strcmp(token, "freq=acs") == 0) { + acs = 1; +#endif /* CONFIG_ACS */ + } else if (sscanf(token, "freq=%d", &freq) == 1) { + continue; } else if (os_strcmp(token, "ht40") == 0) { ht40 = 1; } else if (os_strcmp(token, "vht") == 0) { vht = 1; ht40 = 1; + } else if (os_strcmp(token, "he") == 0) { + he = 1; } else if (os_strcmp(token, "persistent") == 0) { persistent = 1; } else { @@ -5790,6 +6416,26 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) } } +#ifdef CONFIG_ACS + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) && + (acs || freq == 2 || freq == 5)) { + if (freq == 2 && wpa_s->best_24_freq <= 0) { + wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211G; + wpa_s->p2p_go_do_acs = 1; + freq = 0; + } else if (freq == 5 && wpa_s->best_5_freq <= 0) { + wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211A; + wpa_s->p2p_go_do_acs = 1; + freq = 0; + } else { + wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211ANY; + wpa_s->p2p_go_do_acs = 1; + } + } else { + wpa_s->p2p_go_do_acs = 0; + } +#endif /* CONFIG_ACS */ + max_oper_chwidth = parse_freq(chwidth, freq2); if (max_oper_chwidth < 0) return -1; @@ -5797,10 +6443,10 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) if (group_id >= 0) return p2p_ctrl_group_add_persistent(wpa_s, group_id, freq, freq2, ht40, vht, - max_oper_chwidth); + max_oper_chwidth, he); return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, - max_oper_chwidth); + max_oper_chwidth, he); } @@ -5827,10 +6473,24 @@ static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd, } +static int wpas_find_p2p_dev_addr_bss(struct wpa_global *global, + const u8 *p2p_dev_addr) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr)) + return 1; + } + + return 0; +} + + static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { - u8 addr[ETH_ALEN], *addr_ptr; + u8 addr[ETH_ALEN], *addr_ptr, group_capab; int next, res; const struct p2p_peer_info *info; char *pos, *end; @@ -5859,6 +6519,16 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next); if (info == NULL) return -1; + group_capab = info->group_capab; + + if (group_capab && + !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) { + wpa_printf(MSG_DEBUG, + "P2P: Could not find any BSS with p2p_dev_addr " + MACSTR ", hence override group_capab from 0x%x to 0", + MAC2STR(info->p2p_device_addr), group_capab); + group_capab = 0; + } pos = buf; end = buf + buflen; @@ -5884,7 +6554,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, info->serial_number, info->config_methods, info->dev_capab, - info->group_capab, + group_capab, info->level); if (os_snprintf_error(end - pos, res)) return pos - buf; @@ -6165,6 +6835,20 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + if (os_strcmp(cmd, "override_pref_op_chan") == 0) { + int op_class, chan; + + op_class = atoi(param); + param = os_strchr(param, ':'); + if (!param) + return -1; + param++; + chan = atoi(param); + p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class, + chan); + return 0; + } + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); @@ -6176,6 +6860,12 @@ static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s) { os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); wpa_s->force_long_sd = 0; + +#ifdef CONFIG_TESTING_OPTIONS + os_free(wpa_s->get_pref_freq_list_override); + wpa_s->get_pref_freq_list_override = NULL; +#endif /* CONFIG_TESTING_OPTIONS */ + wpas_p2p_stop_find(wpa_s); wpa_s->parent->p2ps_method_config_any = 0; if (wpa_s->global->p2p) @@ -6383,7 +7073,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) u16 id[MAX_ANQP_INFO_ID]; size_t num_id = 0; u32 subtypes = 0; - int get_cell_pref = 0; + u32 mbo_subtypes = 0; used = hwaddr_aton2(dst, dst_addr); if (used < 0) @@ -6404,9 +7094,10 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) } else if (os_strncmp(pos, "mbo:", 4) == 0) { #ifdef CONFIG_MBO int num = atoi(pos + 4); - if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF) + + if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE) return -1; - get_cell_pref = 1; + mbo_subtypes |= BIT(num); #else /* CONFIG_MBO */ return -1; #endif /* CONFIG_MBO */ @@ -6421,11 +7112,11 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) pos++; } - if (num_id == 0) + if (num_id == 0 && !subtypes && !mbo_subtypes) return -1; return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes, - get_cell_pref); + mbo_subtypes); } @@ -6762,6 +7453,9 @@ static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s, autoscan_init(wpa_s, 1); else if (state == WPA_SCANNING) wpa_supplicant_reinit_autoscan(wpa_s); + else + wpa_printf(MSG_DEBUG, "No autoscan update in state %s", + wpa_supplicant_state_txt(state)); return 0; } @@ -6824,26 +7518,41 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd) { int query_reason, list = 0; + char *btm_candidates = NULL; query_reason = atoi(cmd); cmd = os_strchr(cmd, ' '); if (cmd) { - cmd++; - if (os_strncmp(cmd, "list", 4) == 0) { + if (os_strncmp(cmd, " list", 5) == 0) list = 1; - } else { - wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s", - cmd); - return -1; - } + else + btm_candidates = cmd; } wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s", query_reason, list ? " candidate list" : ""); - return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list); + return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, + btm_candidates, + list); +} + + +static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s, + char *cmd) +{ + struct wpabuf *elems; + int ret; + + elems = wpabuf_parse_bin(cmd); + if (!elems) + return -1; + + ret = wnm_send_coloc_intf_report(wpa_s, 0, elems); + wpabuf_free(elems); + return ret; } #endif /* CONFIG_WNM */ @@ -6879,10 +7588,17 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, pos += ret; } - if (si.center_frq1 > 0 && si.center_frq2 > 0) { - ret = os_snprintf(pos, end - pos, - "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n", - si.center_frq1, si.center_frq2); + if (si.center_frq1 > 0) { + ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n", + si.center_frq1); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (si.center_frq2 > 0) { + ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n", + si.center_frq2); if (os_snprintf_error(end - pos, ret)) return -1; pos += ret; @@ -6930,6 +7646,46 @@ static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_TESTING_OPTIONS +int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, + enum wpa_driver_if_type if_type, + unsigned int *num, + unsigned int *freq_list) +{ + char *pos = wpa_s->get_pref_freq_list_override; + char *end; + unsigned int count = 0; + + /* Override string format: + * <if_type1>:<freq1>,<freq2>,... <if_type2>:... */ + + while (pos) { + if (atoi(pos) == (int) if_type) + break; + pos = os_strchr(pos, ' '); + if (pos) + pos++; + } + if (!pos) + return -1; + pos = os_strchr(pos, ':'); + if (!pos) + return -1; + pos++; + end = os_strchr(pos, ' '); + while (pos && (!end || pos < end) && count < *num) { + freq_list[count++] = atoi(pos); + pos = os_strchr(pos, ','); + if (pos) + pos++; + } + + *num = count; + return 0; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + static int wpas_ctrl_iface_get_pref_freq_list( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -6959,7 +7715,7 @@ static int wpas_ctrl_iface_get_pref_freq_list( wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)", - iface_type, buf); + iface_type, cmd); ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list); if (ret) @@ -7116,7 +7872,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); - wpas_abort_ongoing_scan(wpa_s); + if (wpas_abort_ongoing_scan(wpa_s) == 0) + wpa_s->ignore_post_flush_scan_res = 1; if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { /* @@ -7157,6 +7914,22 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; +#ifdef CONFIG_DPP + wpas_dpp_deinit(wpa_s); + wpa_s->dpp_init_max_tries = 0; + wpa_s->dpp_init_retry_time = 0; + wpa_s->dpp_resp_wait_time = 0; + wpa_s->dpp_resp_max_tries = 0; + wpa_s->dpp_resp_retry_time = 0; +#ifdef CONFIG_TESTING_OPTIONS + os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN); + os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN); + dpp_pkex_ephemeral_key_override_len = 0; + dpp_protocol_key_override_len = 0; + dpp_nonce_override_len = 0; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_DPP */ + #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING tdls_testing = 0; @@ -7218,13 +7991,29 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->p2p_go_csa_on_inv = 0; wpa_s->ignore_auth_resp = 0; wpa_s->ignore_assoc_disallow = 0; + wpa_s->testing_resend_assoc = 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; +#ifdef CONFIG_DPP + os_free(wpa_s->dpp_config_obj_override); + wpa_s->dpp_config_obj_override = NULL; + os_free(wpa_s->dpp_discovery_override); + wpa_s->dpp_discovery_override = NULL; + os_free(wpa_s->dpp_groups_override); + wpa_s->dpp_groups_override = NULL; + dpp_test = DPP_TEST_DISABLED; +#endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ wpa_s->disconnected = 0; os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; + os_free(wpa_s->select_network_scan_freqs); + wpa_s->select_network_scan_freqs = NULL; wpa_bss_flush(wpa_s); if (!dl_list_empty(&wpa_s->bss)) { @@ -7242,6 +8031,13 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_SME wpa_s->sme.last_unprot_disconnect.sec = 0; #endif /* CONFIG_SME */ + + wpabuf_free(wpa_s->ric_ies); + wpa_s->ric_ies = NULL; + + wpa_supplicant_update_channel_list(wpa_s, NULL); + + free_bss_tmp_disallowed(wpa_s); } @@ -7539,6 +8335,19 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, goto done; } + pos = os_strstr(params, "bssid="); + if (pos) { + u8 bssid[ETH_ALEN]; + + pos += 6; + if (hwaddr_aton(pos, bssid)) { + wpa_printf(MSG_ERROR, "Invalid BSSID %s", pos); + *reply_len = -1; + goto done; + } + os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN); + } + pos = params; while (pos && *pos != '\0') { if (os_strncmp(pos, "ssid ", 5) == 0) { @@ -7824,6 +8633,124 @@ static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s, + char *param) +{ + struct wpa_scan_res *res; + struct os_reltime now; + char *pos, *end; + int ret = -1; + + if (!param) + return -1; + + if (os_strcmp(param, "START") == 0) { + wpa_bss_update_start(wpa_s); + return 0; + } + + if (os_strcmp(param, "END") == 0) { + wpa_bss_update_end(wpa_s, NULL, 1); + return 0; + } + + if (os_strncmp(param, "BSS ", 4) != 0) + return -1; + param += 3; + + res = os_zalloc(sizeof(*res) + os_strlen(param) / 2); + if (!res) + return -1; + + pos = os_strstr(param, " flags="); + if (pos) + res->flags = strtol(pos + 7, NULL, 16); + + pos = os_strstr(param, " bssid="); + if (pos && hwaddr_aton(pos + 7, res->bssid)) + goto fail; + + pos = os_strstr(param, " freq="); + if (pos) + res->freq = atoi(pos + 6); + + pos = os_strstr(param, " beacon_int="); + if (pos) + res->beacon_int = atoi(pos + 12); + + pos = os_strstr(param, " caps="); + if (pos) + res->caps = strtol(pos + 6, NULL, 16); + + pos = os_strstr(param, " qual="); + if (pos) + res->qual = atoi(pos + 6); + + pos = os_strstr(param, " noise="); + if (pos) + res->noise = atoi(pos + 7); + + pos = os_strstr(param, " level="); + if (pos) + res->level = atoi(pos + 7); + + pos = os_strstr(param, " tsf="); + if (pos) + res->tsf = strtoll(pos + 5, NULL, 16); + + pos = os_strstr(param, " age="); + if (pos) + res->age = atoi(pos + 5); + + pos = os_strstr(param, " est_throughput="); + if (pos) + res->est_throughput = atoi(pos + 16); + + pos = os_strstr(param, " snr="); + if (pos) + res->snr = atoi(pos + 5); + + pos = os_strstr(param, " parent_tsf="); + if (pos) + res->parent_tsf = strtoll(pos + 7, NULL, 16); + + pos = os_strstr(param, " tsf_bssid="); + if (pos && hwaddr_aton(pos + 11, res->tsf_bssid)) + goto fail; + + pos = os_strstr(param, " ie="); + if (pos) { + pos += 4; + end = os_strchr(pos, ' '); + if (!end) + end = pos + os_strlen(pos); + res->ie_len = (end - pos) / 2; + if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len)) + goto fail; + } + + pos = os_strstr(param, " beacon_ie="); + if (pos) { + pos += 11; + end = os_strchr(pos, ' '); + if (!end) + end = pos + os_strlen(pos); + res->beacon_ie_len = (end - pos) / 2; + if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len, + res->beacon_ie_len)) + goto fail; + } + + os_get_reltime(&now); + wpa_bss_update_scan_res(wpa_s, res, &now); + ret = 0; +fail: + os_free(res); + + return ret; +} + + static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; @@ -7854,6 +8781,8 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) wpa_supplicant_event(wpa_s, ev, &event); os_free(event.freq_range.range); return 0; + } else if (os_strcmp(cmd, "SCAN_RES") == 0) { + return wpas_ctrl_iface_driver_scan_res(wpa_s, param); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s", cmd); @@ -7931,26 +8860,39 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, struct iphdr ip; const u8 *pos; unsigned int i; + char extra[30]; - if (len != HWSIM_PACKETLEN) + if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) { + wpa_printf(MSG_DEBUG, + "test data: RX - ignore unexpected length %d", + (int) len); return; + } eth = (const struct ether_header *) buf; os_memcpy(&ip, eth + 1, sizeof(ip)); pos = &buf[sizeof(*eth) + sizeof(ip)]; if (ip.ihl != 5 || ip.version != 4 || - ntohs(ip.tot_len) != HWSIM_IP_LEN) + ntohs(ip.tot_len) > HWSIM_IP_LEN) { + wpa_printf(MSG_DEBUG, + "test data: RX - ignore unexpect IP header"); return; + } - for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) { - if (*pos != (u8) i) + for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) { + if (*pos != (u8) i) { + wpa_printf(MSG_DEBUG, + "test data: RX - ignore mismatching payload"); return; + } pos++; } - - wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR, - MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost)); + extra[0] = '\0'; + if (ntohs(ip.tot_len) != HWSIM_IP_LEN) + os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len)); + wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s", + MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra); } @@ -7994,7 +8936,7 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) { u8 dst[ETH_ALEN], src[ETH_ALEN]; - char *pos; + char *pos, *pos2; int used; long int val; u8 tos; @@ -8003,11 +8945,12 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) struct iphdr *ip; u8 *dpos; unsigned int i; + size_t send_len = HWSIM_IP_LEN; if (wpa_s->l2_test == NULL) return -1; - /* format: <dst> <src> <tos> */ + /* format: <dst> <src> <tos> [len=<length>] */ pos = cmd; used = hwaddr_aton2(pos, dst); @@ -8021,11 +8964,19 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) 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); @@ -8036,17 +8987,17 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) ip->version = 4; ip->ttl = 64; ip->tos = tos; - ip->tot_len = htons(HWSIM_IP_LEN); + ip->tot_len = htons(send_len); ip->protocol = 1; ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); dpos = (u8 *) (ip + 1); - for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) + for (i = 0; i < send_len - sizeof(*ip); i++) *dpos++ = i; if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2], - HWSIM_PACKETLEN) < 0) + sizeof(struct ether_header) + send_len) < 0) return -1; wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR @@ -8218,6 +9169,79 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, return 0; } + +static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s) +{ + u8 zero[WPA_TK_MAX_LEN]; + + if (wpa_s->last_tk_alg == WPA_ALG_NONE) + return -1; + + wpa_printf(MSG_INFO, "TESTING: Reset PN"); + os_memset(zero, 0, sizeof(zero)); + + /* First, use a zero key to avoid any possible duplicate key avoidance + * 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) + 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); +} + + +static int wpas_ctrl_key_request(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos = cmd; + int error, pairwise; + + error = atoi(pos); + pos = os_strchr(pos, ' '); + if (!pos) + return -1; + pairwise = atoi(pos); + wpa_sm_key_request(wpa_s->wpa, error, pairwise); + return 0; +} + + +static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_SME + struct wpa_driver_associate_params params; + int ret; + + os_memset(¶ms, 0, sizeof(params)); + params.bssid = wpa_s->bssid; + params.ssid = wpa_s->sme.ssid; + params.ssid_len = wpa_s->sme.ssid_len; + params.freq.freq = wpa_s->sme.freq; + if (wpa_s->last_assoc_req_wpa_ie) { + params.wpa_ie = wpabuf_head(wpa_s->last_assoc_req_wpa_ie); + params.wpa_ie_len = wpabuf_len(wpa_s->last_assoc_req_wpa_ie); + } + params.pairwise_suite = wpa_s->pairwise_cipher; + params.group_suite = wpa_s->group_cipher; + params.mgmt_group_suite = wpa_s->mgmt_group_cipher; + params.key_mgmt_suite = wpa_s->key_mgmt; + params.wpa_proto = wpa_s->wpa_proto; + params.mgmt_frame_protection = wpa_s->sme.mfp; + params.rrm_used = wpa_s->rrm.rrm_used; + if (wpa_s->sme.prev_bssid_set) + params.prev_bssid = wpa_s->sme.prev_bssid; + wpa_printf(MSG_INFO, "TESTING: Resend association request"); + ret = wpa_drv_associate(wpa_s, ¶ms); + wpa_s->testing_resend_assoc = 1; + return ret; +#else /* CONFIG_SME */ + return -1; +#endif /* CONFIG_SME */ +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -8553,13 +9577,6 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, return -1; } - if ((wpa_s->mac_addr_rand_supported & type) != type) { - wpa_printf(MSG_INFO, - "CTRL: MAC_RAND_SCAN types=%u != supported=%u", - type, wpa_s->mac_addr_rand_supported); - return -1; - } - if (enable > 1) { wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN enable=<0/1> not specified"); @@ -8593,21 +9610,25 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, } if (type & MAC_ADDR_RAND_SCAN) { - wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN, - addr, mask); + if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN, + addr, mask)) + return -1; } if (type & MAC_ADDR_RAND_SCHED_SCAN) { - wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN, - addr, mask); + if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN, + addr, mask)) + return -1; if (wpa_s->sched_scanning && !wpa_s->pno) wpas_scan_restart_sched_scan(wpa_s); } if (type & MAC_ADDR_RAND_PNO) { - wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO, - addr, mask); + if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO, + addr, mask)) + return -1; + if (wpa_s->pno) { wpas_stop_pno(wpa_s); wpas_start_pno(wpa_s); @@ -8641,6 +9662,248 @@ static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) } +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + +static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s, + const char *cmd, char *buf, size_t buflen) +{ + struct rsn_pmksa_cache_entry *entry; + struct wpa_ssid *ssid; + char *pos, *pos2, *end; + int ret; + struct os_reltime now; + + ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd)); + if (!ssid) + return -1; + + pos = buf; + end = buf + buflen; + + os_get_reltime(&now); + + /* + * Entry format: + * <BSSID> <PMKID> <PMK> <reauth_time in seconds> + * <expiration in seconds> <akmp> <opportunistic> + * [FILS Cache Identifier] + */ + + for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry; + entry = entry->next) { + if (entry->network_ctx != ssid) + continue; + + pos2 = pos; + ret = os_snprintf(pos2, end - pos2, MACSTR " ", + MAC2STR(entry->aa)); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + + pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid, + PMKID_LEN); + + ret = os_snprintf(pos2, end - pos2, " "); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + + pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk, + entry->pmk_len); + + ret = os_snprintf(pos2, end - pos2, " %d %d %d %d", + (int) (entry->reauth_time - now.sec), + (int) (entry->expiration - now.sec), + entry->akmp, + entry->opportunistic); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + + if (entry->fils_cache_id_set) { + ret = os_snprintf(pos2, end - pos2, " %02x%02x", + entry->fils_cache_id[0], + entry->fils_cache_id[1]); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + } + + ret = os_snprintf(pos2, end - pos2, "\n"); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + + pos = pos2; + } + + return pos - buf; +} + + +static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s, + char *cmd) +{ + struct rsn_pmksa_cache_entry *entry; + struct wpa_ssid *ssid; + char *pos, *pos2; + int ret = -1; + struct os_reltime now; + int reauth_time = 0, expiration = 0, i; + + /* + * Entry format: + * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> + * <expiration in seconds> <akmp> <opportunistic> + * [FILS Cache Identifier] + */ + + ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd)); + if (!ssid) + return -1; + + pos = os_strchr(cmd, ' '); + if (!pos) + return -1; + pos++; + + entry = os_zalloc(sizeof(*entry)); + if (!entry) + return -1; + + if (hwaddr_aton(pos, entry->aa)) + goto fail; + + pos = os_strchr(pos, ' '); + if (!pos) + goto fail; + pos++; + + if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0) + goto fail; + + pos = os_strchr(pos, ' '); + if (!pos) + goto fail; + pos++; + + pos2 = os_strchr(pos, ' '); + if (!pos2) + goto fail; + entry->pmk_len = (pos2 - pos) / 2; + if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX || + hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0) + goto fail; + + pos = os_strchr(pos, ' '); + if (!pos) + goto fail; + pos++; + + if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration, + &entry->akmp, &entry->opportunistic) != 4) + goto fail; + for (i = 0; i < 4; i++) { + pos = os_strchr(pos, ' '); + if (!pos) { + if (i < 3) + goto fail; + break; + } + pos++; + } + if (pos) { + if (hexstr2bin(pos, entry->fils_cache_id, + FILS_CACHE_ID_LEN) < 0) + goto fail; + entry->fils_cache_id_set = 1; + } + os_get_reltime(&now); + entry->expiration = now.sec + expiration; + entry->reauth_time = now.sec + reauth_time; + + entry->network_ctx = ssid; + + wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); + entry = NULL; + ret = 0; +fail: + os_free(entry); + return ret; +} + + +#ifdef CONFIG_MESH + +static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s, + const char *cmd, char *buf, + size_t buflen) +{ + u8 spa[ETH_ALEN]; + + if (!wpa_s->ifmsh) + return -1; + + if (os_strcasecmp(cmd, "any") == 0) + return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen); + + if (hwaddr_aton(cmd, spa)) + return -1; + + return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen); +} + + +static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s, + char *cmd) +{ + /* + * We do not check mesh interface existance because PMKSA should be + * stored before wpa_s->ifmsh creation to suppress commit message + * creation. + */ + return wpas_ap_pmksa_cache_add_external(wpa_s, cmd); +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + +#ifdef CONFIG_FILS +static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct fils_hlp_req *req; + const char *pos; + + /* format: <dst> <packet starting from ethertype> */ + + req = os_zalloc(sizeof(*req)); + if (!req) + return -1; + + if (hwaddr_aton(cmd, req->dst)) + goto fail; + + pos = os_strchr(cmd, ' '); + if (!pos) + goto fail; + pos++; + req->pkt = wpabuf_parse_bin(pos); + if (!req->pkt) + goto fail; + + dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list); + return 0; +fail: + wpabuf_free(req->pkt); + os_free(req); + return -1; +} +#endif /* CONFIG_FILS */ + + static int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || @@ -8662,7 +9925,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, int reply_len; if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || - os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + os_strncmp(buf, "SET_NETWORK ", 12) == 0 || + os_strncmp(buf, "PMKSA_ADD ", 10) == 0 || + os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) { if (wpa_debug_show_keys) wpa_dbg(wpa_s, MSG_DEBUG, "Control interface command '%s'", buf); @@ -8671,7 +9936,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, "Control interface command '%s [REMOVED]'", os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ? - WPA_CTRL_RSP : "SET_NETWORK"); + WPA_CTRL_RSP : + (os_strncmp(buf, "SET_NETWORK ", 12) == 0 ? + "SET_NETWORK" : "key-add")); } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) { wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", @@ -8707,6 +9974,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len += eapol_sm_get_mib(wpa_s->eapol, reply + reply_len, reply_size - reply_len); +#ifdef CONFIG_MACSEC + reply_len += ieee802_1x_kay_get_mib( + wpa_s->kay, reply + reply_len, + reply_size - reply_len); +#endif /* CONFIG_MACSEC */ } } else if (os_strncmp(buf, "STATUS", 6) == 0) { reply_len = wpa_supplicant_ctrl_iface_status( @@ -8715,6 +9987,22 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size); } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { wpas_ctrl_iface_pmksa_flush(wpa_s); +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) { + reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10, + reply, reply_size); + } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) { + if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0) + reply_len = -1; +#ifdef CONFIG_MESH + } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) { + reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15, + reply, reply_size); + } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) { + if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0) + reply_len = -1; +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; @@ -8751,11 +10039,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) reply_len = -1; #endif /* IEEE8021X_EAPOL */ -#ifdef CONFIG_PEERKEY - } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { - if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) - reply_len = -1; -#endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211R } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) @@ -9286,6 +10569,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) { if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14)) reply_len = -1; + } else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) { + if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) + reply_len = -1; #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); @@ -9332,6 +10618,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) reply_len = -1; + } else if (os_strcmp(buf, "RESET_PN") == 0) { + if (wpas_ctrl_reset_pn(wpa_s) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "KEY_REQUEST ", 12) == 0) { + if (wpas_ctrl_key_request(wpa_s, buf + 12) < 0) + reply_len = -1; + } 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) @@ -9353,6 +10654,98 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) { reply_len = wpas_ctrl_iface_get_pref_freq_list( wpa_s, buf + 19, reply, reply_size); +#ifdef CONFIG_FILS + } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) { + if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17)) + reply_len = -1; + } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) { + wpas_flush_fils_hlp_req(wpa_s); +#endif /* CONFIG_FILS */ +#ifdef CONFIG_DPP + } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) { + int res; + + res = wpas_dpp_qr_code(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_BOOTSTRAP_GEN ", 18) == 0) { + int res; + + res = dpp_bootstrap_gen(wpa_s->dpp, buf + 18); + 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_REMOVE ", 21) == 0) { + if (dpp_bootstrap_remove(wpa_s->dpp, buf + 21) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) { + const char *uri; + + uri = dpp_bootstrap_get_uri(wpa_s->dpp, atoi(buf + 22)); + if (!uri) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%s", uri); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } + } 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_AUTH_INIT ", 14) == 0) { + if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) { + if (wpas_dpp_listen(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) { + wpas_dpp_stop(wpa_s); + wpas_dpp_listen_stop(wpa_s); + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) { + int res; + + res = dpp_configurator_add(wpa_s->dpp, 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_CONFIGURATOR_REMOVE ", 24) == 0) { + if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) { + if (wpas_dpp_configurator_sign(wpa_s, buf + 21) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) { + reply_len = dpp_configurator_get_key_id(wpa_s->dpp, + atoi(buf + 25), + reply, reply_size); + } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) { + int res; + + res = wpas_dpp_pkex_add(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_PKEX_REMOVE ", 16) == 0) { + if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0) + reply_len = -1; +#endif /* CONFIG_DPP */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -9662,12 +11055,16 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, "P2P_CANCEL", "P2P_PRESENCE_REQ", "P2P_EXT_LISTEN", +#ifdef CONFIG_AP + "STA-FIRST", +#endif /* CONFIG_AP */ NULL }; static const char * prefix[] = { #ifdef ANDROID "DRIVER ", #endif /* ANDROID */ + "GET_CAPABILITY ", "GET_NETWORK ", "REMOVE_NETWORK ", "P2P_FIND ", @@ -9699,6 +11096,10 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, "NFC_REPORT_HANDOVER ", "P2P_ASP_PROVISION ", "P2P_ASP_PROVISION_RESP ", +#ifdef CONFIG_AP + "STA ", + "STA-NEXT ", +#endif /* CONFIG_AP */ NULL }; int found = 0; diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c index 54e0e2fac583..9c0a47e63936 100644 --- a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c +++ b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c @@ -319,13 +319,12 @@ static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) } os_free(dst->rsp_buf); - dst->rsp_buf = os_malloc(send_len); + dst->rsp_buf = os_memdup(send_buf, send_len); if (dst->rsp_buf == NULL) { ctrl_close_pipe(dst); os_free(reply); return; } - os_memcpy(dst->rsp_buf, send_buf, send_len); os_free(reply); if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, @@ -739,13 +738,12 @@ static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, } os_free(dst->rsp_buf); - dst->rsp_buf = os_malloc(send_len); + dst->rsp_buf = os_memdup(send_buf, send_len); if (dst->rsp_buf == NULL) { global_close_pipe(dst); os_free(reply); return; } - os_memcpy(dst->rsp_buf, send_buf, send_len); os_free(reply); if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c index 0dc0937ff0aa..8a6057a82bfe 100644 --- a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c +++ b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c @@ -219,7 +219,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, { struct wpa_supplicant *wpa_s = eloop_ctx; struct ctrl_iface_priv *priv = sock_ctx; - char buf[256], *pos; + char buf[4096], *pos; int res; #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 from; @@ -600,7 +600,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, { struct wpa_global *global = eloop_ctx; struct ctrl_iface_global_priv *priv = sock_ctx; - char buf[256], *pos; + char buf[4096], *pos; int res; #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 from; diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c index 4db712fff7bb..71fe7ed6bef5 100644 --- a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c +++ b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c @@ -103,7 +103,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, socklen_t fromlen, int global) { - return ctrl_iface_attach(ctrl_dst, from, fromlen); + return ctrl_iface_attach(ctrl_dst, from, fromlen, NULL); } @@ -570,8 +570,8 @@ static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s, } } - if (gid_set && chown(dir, -1, gid) < 0) { - wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", + if (gid_set && lchown(dir, -1, gid) < 0) { + wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s", dir, (int) gid, strerror(errno)); goto fail; } @@ -638,8 +638,8 @@ static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s, } } - if (gid_set && chown(fname, -1, gid) < 0) { - wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", + if (gid_set && lchown(fname, -1, gid) < 0) { + wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s", fname, (int) gid, strerror(errno)); goto fail; } @@ -1235,9 +1235,9 @@ static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global, wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", (int) gid); } - if (chown(ctrl, -1, gid) < 0) { + if (lchown(ctrl, -1, gid) < 0) { wpa_printf(MSG_ERROR, - "chown[global_ctrl_interface=%s,gid=%d]: %s", + "lchown[global_ctrl_interface=%s,gid=%d]: %s", ctrl, (int) gid, strerror(errno)); goto fail; } diff --git a/contrib/wpa/wpa_supplicant/dbus/Makefile b/contrib/wpa/wpa_supplicant/dbus/Makefile index f355ebef51d2..4d8700428dcb 100644 --- a/contrib/wpa/wpa_supplicant/dbus/Makefile +++ b/contrib/wpa/wpa_supplicant/dbus/Makefile @@ -36,7 +36,6 @@ CFLAGS += -DCONFIG_WPS endif CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW -CFLAGS += -DCONFIG_CTRL_IFACE_DBUS ifndef DBUS_LIBS DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) @@ -54,8 +53,6 @@ CFLAGS += $(DBUS_INCLUDE) LIB_OBJS= \ dbus_common.o \ - dbus_old.o \ - dbus_old_handlers.o \ dbus_new.o \ dbus_new_handlers.o \ dbus_new_helpers.o \ @@ -63,7 +60,6 @@ LIB_OBJS= \ dbus_dict_helpers.o ifdef CONFIG_WPS -LIB_OBJS += dbus_old_handlers_wps.o LIB_OBJS += dbus_new_handlers_wps.o endif diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf index 382dcb34318c..e81b495f4b99 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf +++ b/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf @@ -3,11 +3,6 @@ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <policy user="root"> - <allow own="fi.epitest.hostap.WPASupplicant"/> - - <allow send_destination="fi.epitest.hostap.WPASupplicant"/> - <allow send_interface="fi.epitest.hostap.WPASupplicant"/> - <allow own="fi.w1.wpa_supplicant1"/> <allow send_destination="fi.w1.wpa_supplicant1"/> @@ -15,9 +10,6 @@ <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> </policy> <policy context="default"> - <deny own="fi.epitest.hostap.WPASupplicant"/> - <deny send_destination="fi.epitest.hostap.WPASupplicant"/> - <deny own="fi.w1.wpa_supplicant1"/> <deny send_destination="fi.w1.wpa_supplicant1"/> <deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c index 7ef6cad62aaf..efa6c7b20595 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c @@ -16,7 +16,6 @@ #include "dbus_common.h" #include "dbus_common_i.h" #include "dbus_new.h" -#include "dbus_old.h" #include "../wpa_supplicant_i.h" @@ -351,9 +350,6 @@ struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global) #ifdef CONFIG_CTRL_IFACE_DBUS_NEW wpas_dbus_ctrl_iface_init(priv) < 0 || #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ -#ifdef CONFIG_CTRL_IFACE_DBUS - wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 || -#endif /* CONFIG_CTRL_IFACE_DBUS */ wpas_dbus_init_common_finish(priv) < 0) { wpas_dbus_deinit(priv); return NULL; @@ -372,9 +368,5 @@ void wpas_dbus_deinit(struct wpas_dbus_priv *priv) wpas_dbus_ctrl_iface_deinit(priv); #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ -#ifdef CONFIG_CTRL_IFACE_DBUS - /* TODO: is any deinit needed? */ -#endif /* CONFIG_CTRL_IFACE_DBUS */ - wpas_dbus_deinit_common(priv); } diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c index 27b3012aede8..fc2fc2ef1b96 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c @@ -13,6 +13,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" #include "wps/wps.h" +#include "ap/sta_info.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../bss.h" @@ -128,7 +129,8 @@ void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv) * Notify listeners about event related with interface */ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s, - const char *sig_name, int properties) + const char *sig_name, + dbus_bool_t properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; @@ -230,7 +232,7 @@ void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success) */ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s, const char *bss_obj_path, - const char *sig_name, int properties) + const char *sig_name, dbus_bool_t properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; @@ -364,7 +366,7 @@ void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, */ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s, int id, const char *sig_name, - int properties) + dbus_bool_t properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; @@ -793,6 +795,144 @@ nomem: #endif /* CONFIG_WPS */ + +#ifdef CONFIG_MESH + +void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_MESH, + "MeshGroupStarted"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID", + (const char *) ssid->ssid, + ssid->ssid_len) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s, + const u8 *meshid, u8 meshid_len, + int reason) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_MESH, + "MeshGroupRemoved"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID", + (const char *) meshid, + meshid_len) || + !wpa_dbus_dict_append_int32(&dict_iter, "DisconnectReason", + reason) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_MESH, + "MeshPeerConnected"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "PeerAddress", + (const char *) peer_addr, + ETH_ALEN) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int reason) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_MESH, + "MeshPeerDisconnected"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "PeerAddress", + (const char *) peer_addr, + ETH_ALEN) || + !wpa_dbus_dict_append_int32(&dict_iter, "DisconnectReason", + reason) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + +#endif /* CONFIG_MESH */ + + void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *altsubject[], @@ -939,6 +1079,79 @@ void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s, } +/** + * wpas_dbus_signal_station - Send an event signal related to a station object + * @wpa_s: %wpa_supplicant network interface data + * @station_obj_path: Station object path + * @sig_name: signal name - StationAdded or StationRemoved + * @properties: Whether to add second argument with object properties + * + * Notify listeners about event related with station. + */ +static void wpas_dbus_signal_station(struct wpa_supplicant *wpa_s, + const char *station_obj_path, + const char *sig_name, + dbus_bool_t properties) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + wpa_printf(MSG_DEBUG, "dbus: STA signal %s", sig_name); + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &station_obj_path) || + (properties && + !wpa_dbus_get_object_properties(iface, station_obj_path, + WPAS_DBUS_NEW_IFACE_STA, + &iter))) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_station_added - Send a Station added signal + * @wpa_s: %wpa_supplicant network interface data + * @station_obj_path: new Station object path + * + * Notify listeners about adding new Station + */ +static void wpas_dbus_signal_station_added(struct wpa_supplicant *wpa_s, + const char *station_obj_path) +{ + wpas_dbus_signal_station(wpa_s, station_obj_path, "StationAdded", TRUE); +} + + +/** + * wpas_dbus_signal_station_removed - Send a Station removed signal + * @wpa_s: %wpa_supplicant network interface data + * @station_obj_path: Station object path + * + * Notify listeners about removing Station + */ +static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s, + const char *station_obj_path) +{ + wpas_dbus_signal_station(wpa_s, station_obj_path, "StationRemoved", + FALSE); +} + + #ifdef CONFIG_P2P /** @@ -1256,9 +1469,12 @@ static void peer_groups_changed(struct wpa_supplicant *wpa_s) * @wpa_s: %wpa_supplicant network interface data * @client: this device is P2P client * @persistent: 0 - non persistent group, 1 - persistent group + * @ip: When group role is client, it contains local IP address, netmask, and + * GO's IP address, if assigned; otherwise, NULL */ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, - int client, int persistent) + int client, int persistent, + const u8 *ip) { DBusMessage *msg; DBusMessageIter iter, dict_iter; @@ -1300,6 +1516,13 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) || !wpa_dbus_dict_append_object_path(&dict_iter, "group_object", wpa_s->dbus_groupobj_path) || + (ip && + (!wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddr", + (char *) ip, 4) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask", + (char *) ip + 4, 4) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo", + (char *) ip + 8, 4))) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) { wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); } else { @@ -1734,7 +1957,7 @@ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, */ static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s, int id, const char *sig_name, - int properties) + dbus_bool_t properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; @@ -1879,6 +2102,9 @@ void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s, if (iface == NULL) return; + if (wpa_s->p2p_mgmt) + wpa_s = wpa_s->parent; + msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "GroupFormationFailure"); @@ -1920,6 +2146,9 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, if (iface == NULL) return; + if (wpa_s->p2p_mgmt) + wpa_s = wpa_s->parent; + msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "InvitationReceived"); @@ -1992,6 +2221,9 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, case WPAS_DBUS_PROP_BSSS: prop = "BSSs"; break; + case WPAS_DBUS_PROP_STATIONS: + prop = "Stations"; + break; case WPAS_DBUS_PROP_CURRENT_AUTH_MODE: prop = "CurrentAuthMode"; break; @@ -1999,10 +2231,26 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, prop = "DisconnectReason"; flush = TRUE; break; + case WPAS_DBUS_PROP_AUTH_STATUS_CODE: + prop = "AuthStatusCode"; + flush = TRUE; + break; case WPAS_DBUS_PROP_ASSOC_STATUS_CODE: prop = "AssocStatusCode"; flush = TRUE; break; + case WPAS_DBUS_PROP_ROAM_TIME: + prop = "RoamTime"; + break; + case WPAS_DBUS_PROP_ROAM_COMPLETE: + prop = "RoamComplete"; + break; + case WPAS_DBUS_PROP_SESSION_LENGTH: + prop = "SessionLength"; + break; + case WPAS_DBUS_PROP_BSS_TM_STATUS: + prop = "BSSTMStatus"; + break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); @@ -2085,6 +2333,41 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s, /** + * wpas_dbus_sta_signal_prop_changed - Signals change of STA property + * @wpa_s: %wpa_supplicant network interface data + * @property: indicates which property has changed + * @address: unique BSS identifier + * + * Sends PropertyChanged signals with path, interface, and arguments depending + * on which property has changed. + */ +void wpas_dbus_sta_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_bss_prop property, + u8 address[ETH_ALEN]) +{ + char path[WPAS_DBUS_OBJECT_PATH_MAX]; + char *prop; + + switch (property) { + case WPAS_DBUS_STA_PROP_ADDRESS: + prop = "Address"; + break; + default: + wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", + __func__, property); + return; + } + + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(address)); + + wpa_dbus_mark_property_changed(wpa_s->global->dbus, path, + WPAS_DBUS_NEW_IFACE_STA, prop); +} + + +/** * wpas_dbus_signal_debug_level_changed - Signals change of debug param * @global: wpa_global structure * @@ -2572,6 +2855,30 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = { 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 } }; @@ -2698,6 +3005,157 @@ err: } +static const struct wpa_dbus_property_desc wpas_dbus_sta_properties[] = { + { "Address", WPAS_DBUS_NEW_IFACE_STA, "ay", + wpas_dbus_getter_sta_address, + NULL, NULL + }, + { "AID", WPAS_DBUS_NEW_IFACE_STA, "q", + wpas_dbus_getter_sta_aid, + NULL, NULL + }, + { "Capabilities", WPAS_DBUS_NEW_IFACE_STA, "q", + wpas_dbus_getter_sta_caps, + NULL, NULL + }, + { "RxPackets", WPAS_DBUS_NEW_IFACE_STA, "t", + wpas_dbus_getter_sta_rx_packets, + NULL, NULL + }, + { "TxPackets", WPAS_DBUS_NEW_IFACE_STA, "t", + wpas_dbus_getter_sta_tx_packets, + NULL, NULL + }, + { "RxBytes", WPAS_DBUS_NEW_IFACE_STA, "t", + wpas_dbus_getter_sta_rx_bytes, + NULL, NULL + }, + { "TxBytes", WPAS_DBUS_NEW_IFACE_STA, "t", + wpas_dbus_getter_sta_tx_bytes, + NULL, NULL + }, + { NULL, NULL, NULL, NULL, NULL, NULL } +}; + + +static const struct wpa_dbus_signal_desc wpas_dbus_sta_signals[] = { + /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ + { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_STA, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { NULL, NULL, { END_ARGS } } +}; + + +/** + * wpas_dbus_unregister_sta - Unregister a connected station from dbus + * @wpa_s: wpa_supplicant interface structure + * @sta: station MAC address + * Returns: 0 on success, -1 on failure + * + * Unregisters STA representing object from dbus. + */ +int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta) +{ + struct wpas_dbus_priv *ctrl_iface; + char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + + /* Do nothing if the control interface is not turned on */ + if (!wpa_s || !wpa_s->global) + return 0; + ctrl_iface = wpa_s->global->dbus; + if (!ctrl_iface) + return 0; + + os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(sta)); + + wpa_printf(MSG_DEBUG, "dbus: Unregister STA object '%s'", + station_obj_path); + if (wpa_dbus_unregister_object_per_iface(ctrl_iface, + station_obj_path)) { + wpa_printf(MSG_ERROR, "dbus: Cannot unregister STA object %s", + station_obj_path); + return -1; + } + + wpas_dbus_signal_station_removed(wpa_s, station_obj_path); + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS); + + return 0; +} + + +/** + * wpas_dbus_register_sta - Register a connected station with dbus + * @wpa_s: wpa_supplicant interface structure + * @sta: station MAC address + * Returns: 0 on success, -1 on failure + * + * Registers STA representing object with dbus. + */ +int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta) +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + struct sta_handler_args *arg; + + /* Do nothing if the control interface is not turned on */ + if (!wpa_s || !wpa_s->global) + return 0; + ctrl_iface = wpa_s->global->dbus; + if (!ctrl_iface) + return 0; + + os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(sta)); + + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); + if (!obj_desc) { + wpa_printf(MSG_ERROR, + "Not enough memory to create object description"); + goto err; + } + + arg = os_zalloc(sizeof(struct sta_handler_args)); + if (!arg) { + wpa_printf(MSG_ERROR, + "Not enough memory to create arguments for handler"); + goto err; + } + arg->wpa_s = wpa_s; + arg->sta = sta; + + wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, + wpas_dbus_sta_properties, wpas_dbus_sta_signals); + + wpa_printf(MSG_DEBUG, "dbus: Register STA object '%s'", + station_obj_path); + if (wpa_dbus_register_object_per_iface(ctrl_iface, station_obj_path, + wpa_s->ifname, obj_desc)) { + wpa_printf(MSG_ERROR, + "Cannot register STA dbus object %s", + station_obj_path); + goto err; + } + + wpas_dbus_signal_station_added(wpa_s, station_obj_path); + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS); + + return 0; + +err: + free_dbus_object_desc(obj_desc); + return -1; +} + + static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_scan, @@ -3071,6 +3529,20 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { END_ARGS } }, + { "TDLSChannelSwitch", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_tdls_channel_switch, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "TDLSCancelChannelSwitch", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_tdls_cancel_channel_switch, + { + { "peer_address", "s", ARG_IN }, + END_ARGS + } + }, #endif /* CONFIG_TDLS */ { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add, @@ -3104,6 +3576,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { } }, #endif /* CONFIG_NO_CONFIG_WRITE */ + { "AbortScan", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_abort_scan, + { + END_ARGS + } + }, { NULL, NULL, NULL, { END_ARGS } } }; @@ -3224,6 +3702,42 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { wpas_dbus_setter_config_methods, NULL }, + { + "DeviceName", WPAS_DBUS_NEW_IFACE_WPS, "s", + wpas_dbus_getter_wps_device_name, + wpas_dbus_setter_wps_device_name, + NULL + }, + { + "Manufacturer", WPAS_DBUS_NEW_IFACE_WPS, "s", + wpas_dbus_getter_wps_manufacturer, + wpas_dbus_setter_wps_manufacturer, + NULL + }, + { + "ModelName", WPAS_DBUS_NEW_IFACE_WPS, "s", + wpas_dbus_getter_wps_device_model_name, + wpas_dbus_setter_wps_device_model_name, + NULL + }, + { + "ModelNumber", WPAS_DBUS_NEW_IFACE_WPS, "s", + wpas_dbus_getter_wps_device_model_number, + wpas_dbus_setter_wps_device_model_number, + NULL + }, + { + "SerialNumber", WPAS_DBUS_NEW_IFACE_WPS, "s", + wpas_dbus_getter_wps_device_serial_number, + wpas_dbus_setter_wps_device_serial_number, + NULL + }, + { + "DeviceType", WPAS_DBUS_NEW_IFACE_WPS, "ay", + wpas_dbus_getter_wps_device_device_type, + wpas_dbus_setter_wps_device_device_type, + NULL + }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}", @@ -3262,11 +3776,33 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { NULL, NULL }, + { "AuthStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", + wpas_dbus_getter_auth_status_code, + NULL, + NULL + }, { "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", wpas_dbus_getter_assoc_status_code, NULL, NULL }, +#ifdef CONFIG_MESH + { "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay", + wpas_dbus_getter_mesh_peers, + NULL, + NULL + }, + { "MeshGroup", WPAS_DBUS_NEW_IFACE_MESH, "ay", + wpas_dbus_getter_mesh_group, + NULL, + NULL + }, +#endif /* CONFIG_MESH */ + { "Stations", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", + wpas_dbus_getter_stas, + NULL, + NULL + }, { NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -3536,6 +4072,19 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { END_ARGS } }, + { "StationAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "StationRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, @@ -3544,6 +4093,32 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { END_ARGS } }, +#ifdef CONFIG_MESH + { "MeshGroupStarted", WPAS_DBUS_NEW_IFACE_MESH, + { + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "MeshGroupRemoved", WPAS_DBUS_NEW_IFACE_MESH, + { + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "MeshPeerConnected", WPAS_DBUS_NEW_IFACE_MESH, + { + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "MeshPeerDisconnected", WPAS_DBUS_NEW_IFACE_MESH, + { + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_MESH */ { NULL, NULL, { END_ARGS } } }; @@ -3790,6 +4365,11 @@ static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = { NULL, NULL }, + { "VSIE", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", + wpas_dbus_getter_p2p_peer_vsie, + NULL, + NULL + }, { NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -3818,7 +4398,7 @@ static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = { */ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr, const char *interface, - const char *sig_name, int properties) + const char *sig_name, dbus_bool_t properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; @@ -4012,7 +4592,13 @@ void wpas_dbus_signal_p2p_find_stopped(struct wpa_supplicant *wpa_s) iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ - if (iface == NULL || !wpa_s->dbus_new_path) + if (iface == NULL) + return; + + if (wpa_s->p2p_mgmt) + wpa_s = wpa_s->parent; + + if (!wpa_s->dbus_new_path) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h index d64fceef718c..42db3892ed77 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h @@ -28,8 +28,14 @@ enum wpas_dbus_prop { WPAS_DBUS_PROP_CURRENT_NETWORK, WPAS_DBUS_PROP_CURRENT_AUTH_MODE, WPAS_DBUS_PROP_BSSS, + WPAS_DBUS_PROP_STATIONS, WPAS_DBUS_PROP_DISCONNECT_REASON, + WPAS_DBUS_PROP_AUTH_STATUS_CODE, WPAS_DBUS_PROP_ASSOC_STATUS_CODE, + WPAS_DBUS_PROP_ROAM_TIME, + WPAS_DBUS_PROP_ROAM_COMPLETE, + WPAS_DBUS_PROP_SESSION_LENGTH, + WPAS_DBUS_PROP_BSS_TM_STATUS, }; enum wpas_dbus_bss_prop { @@ -45,6 +51,10 @@ enum wpas_dbus_bss_prop { WPAS_DBUS_BSS_PROP_AGE, }; +enum wpas_dbus_sta_prop { + WPAS_DBUS_STA_PROP_ADDRESS, +}; + #define WPAS_DBUS_OBJECT_PATH_MAX 150 #define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1" @@ -61,9 +71,14 @@ enum wpas_dbus_bss_prop { #define WPAS_DBUS_NEW_BSSIDS_PART "BSSs" #define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS" +#define WPAS_DBUS_NEW_STAS_PART "Stations" +#define WPAS_DBUS_NEW_IFACE_STA WPAS_DBUS_NEW_INTERFACE ".Station" + #define WPAS_DBUS_NEW_IFACE_P2PDEVICE \ WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice" +#define WPAS_DBUS_NEW_IFACE_MESH WPAS_DBUS_NEW_IFACE_INTERFACE ".Mesh" + /* * Groups correspond to P2P groups where this device is a GO (owner) */ @@ -161,6 +176,8 @@ int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id); int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id); +int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta); +int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta); void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, const char *name); void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, @@ -190,7 +207,8 @@ void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id, u8 go_intent); void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, - int client, int persistent); + int client, int persistent, + const u8 *ip); void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s, const char *reason); void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, @@ -237,6 +255,15 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *dev_addr, const u8 *bssid, int id, int op_freq); +void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s, + const u8 *meshid, u8 meshid_len, + int reason); +void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr); +void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int reason); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ @@ -333,6 +360,18 @@ static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, return 0; } +static inline int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, + const u8 *sta) +{ + return 0; +} + +static inline int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, + const u8 *sta) +{ + return 0; +} + static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, const char *name) { @@ -400,7 +439,8 @@ static inline void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, static inline void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, - int client, int persistent) + int client, int persistent, + const u8 *ip) { } @@ -551,6 +591,31 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, { } +static inline +void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ +} + +static inline +void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s, + const u8 *meshid, u8 meshid_len, + int reason) +{ +} + +static inline +void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr) +{ +} + +static inline +void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int reason) +{ +} + #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c index e11dd36ca23c..6c36d91a0cf8 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c @@ -15,6 +15,9 @@ #include "eap_peer/eap_methods.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" +#include "ap/hostapd.h" +#include "ap/sta_info.h" +#include "ap/ap_drv_ops.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../driver_i.h" @@ -22,12 +25,17 @@ #include "../bss.h" #include "../scan.h" #include "../autoscan.h" +#include "../ap.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" #include "dbus_dict_helpers.h" #include "dbus_common_i.h" #include "drivers/driver.h" +#ifdef CONFIG_MESH +#include "ap/hostapd.h" +#include "ap/sta_info.h" +#endif /* CONFIG_MESH */ static const char * const debug_strings[] = { "excessive", "msgdump", "debug", "info", "warning", "error", NULL @@ -517,6 +525,27 @@ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, /** + * wpas_dbus_string_property_getter - Get string type property + * @iter: Message iter to use when appending arguments + * @val: Pointer to place holding property value, can be %NULL + * @error: On failure an error describing the failure + * Returns: TRUE if the request was successful, FALSE if it failed + * + * Generic getter for string type properties. %NULL is converted to an empty + * string. + */ +dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter, + const void *val, + DBusError *error) +{ + if (!val) + val = ""; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &val, error); +} + + +/** * wpas_dbus_handler_create_interface - Request registration of a network iface * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure @@ -955,8 +984,21 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { - const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL }; + const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; size_t num_items = 0; +#ifdef CONFIG_FILS + struct wpa_global *global = user_data; + struct wpa_supplicant *wpa_s; + int fils_supported = 0, fils_sk_pfs_supported = 0; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_is_fils_supported(wpa_s)) + fils_supported = 1; + if (wpa_is_fils_sk_pfs_supported(wpa_s)) + fils_sk_pfs_supported = 1; + } +#endif /* CONFIG_FILS */ #ifdef CONFIG_AP capabilities[num_items++] = "ap"; @@ -970,6 +1012,24 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( #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 */ +#ifdef CONFIG_FILS + if (fils_supported) + capabilities[num_items++] = "fils"; + if (fils_sk_pfs_supported) + capabilities[num_items++] = "fils_sk_pfs"; +#endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211R + capabilities[num_items++] = "ft"; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SHA384 + capabilities[num_items++] = "sha384"; +#endif /* CONFIG_SHA384 */ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, @@ -1052,12 +1112,11 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, } if (len != 0) { - ssid = os_malloc(len); + ssid = os_memdup(val, len); if (ssid == NULL) { *reply = wpas_dbus_error_no_memory(message); return -1; } - os_memcpy(ssid, val, len); } else { /* Allow zero-length SSIDs */ ssid = NULL; @@ -1396,6 +1455,27 @@ out: } +/* + * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: Abort failed or no scan in progress DBus error message on failure + * or NULL otherwise. + * + * Handler function for "AbortScan" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpas_abort_ongoing_scan(wpa_s) < 0) + return dbus_message_new_error( + message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR, + "Abort failed or no scan in progress"); + + return NULL; +} + + /** * wpas_dbus_handler_signal_poll - Request immediate signal properties * @message: Pointer to incoming dbus message @@ -1903,13 +1983,12 @@ DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, goto err; } - blob->data = os_malloc(blob_len); + blob->data = os_memdup(blob_data, blob_len); blob->name = os_strdup(blob_name); if (!blob->data || !blob->name) { reply = wpas_dbus_error_no_memory(message); goto err; } - os_memcpy(blob->data, blob_data, blob_len); blob->len = blob_len; wpa_config_set_blob(wpa_s->conf, blob); @@ -2270,6 +2349,156 @@ DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, return NULL; } +/* + * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "TDLSChannelSwitch" method call of network interface. + */ +DBusMessage * +wpas_dbus_handler_tdls_channel_switch(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter, iter_dict; + struct wpa_dbus_dict_entry entry; + u8 peer[ETH_ALEN]; + struct hostapd_freq_params freq_params; + u8 oper_class = 0; + int ret; + int is_peer_present = 0; + + if (!wpa_tdls_is_external_setup(wpa_s->wpa)) { + wpa_printf(MSG_INFO, + "tdls_chanswitch: Only supported with external setup"); + return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup"); + } + + os_memset(&freq_params, 0, sizeof(freq_params)); + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + return wpas_dbus_error_invalid_args(message, NULL); + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + return wpas_dbus_error_invalid_args(message, NULL); + + if (os_strcmp(entry.key, "PeerAddress") == 0 && + entry.type == DBUS_TYPE_STRING) { + if (hwaddr_aton(entry.str_value, peer)) { + wpa_printf(MSG_DEBUG, + "tdls_chanswitch: Invalid address '%s'", + entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + return wpas_dbus_error_invalid_args(message, + NULL); + } + + is_peer_present = 1; + } else if (os_strcmp(entry.key, "OperClass") == 0 && + entry.type == DBUS_TYPE_BYTE) { + oper_class = entry.byte_value; + } else if (os_strcmp(entry.key, "Frequency") == 0 && + entry.type == DBUS_TYPE_UINT32) { + freq_params.freq = entry.uint32_value; + } else if (os_strcmp(entry.key, "SecChannelOffset") == 0 && + entry.type == DBUS_TYPE_UINT32) { + freq_params.sec_channel_offset = entry.uint32_value; + } else if (os_strcmp(entry.key, "CenterFrequency1") == 0 && + entry.type == DBUS_TYPE_UINT32) { + freq_params.center_freq1 = entry.uint32_value; + } else if (os_strcmp(entry.key, "CenterFrequency2") == 0 && + entry.type == DBUS_TYPE_UINT32) { + freq_params.center_freq2 = entry.uint32_value; + } else if (os_strcmp(entry.key, "Bandwidth") == 0 && + entry.type == DBUS_TYPE_UINT32) { + freq_params.bandwidth = entry.uint32_value; + } else if (os_strcmp(entry.key, "HT") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + freq_params.ht_enabled = entry.bool_value; + } else if (os_strcmp(entry.key, "VHT") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + freq_params.vht_enabled = entry.bool_value; + } else { + wpa_dbus_dict_entry_clear(&entry); + return wpas_dbus_error_invalid_args(message, NULL); + } + + wpa_dbus_dict_entry_clear(&entry); + } + + if (oper_class == 0) { + wpa_printf(MSG_INFO, + "tdls_chanswitch: Invalid op class provided"); + return wpas_dbus_error_invalid_args( + message, "Invalid op class provided"); + } + + if (freq_params.freq == 0) { + wpa_printf(MSG_INFO, + "tdls_chanswitch: Invalid freq provided"); + return wpas_dbus_error_invalid_args(message, + "Invalid freq provided"); + } + + if (is_peer_present == 0) { + wpa_printf(MSG_DEBUG, + "tdls_chanswitch: peer address not provided"); + return wpas_dbus_error_invalid_args( + message, "peer address not provided"); + } + + wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR + " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s", + MAC2STR(peer), oper_class, freq_params.freq, + freq_params.center_freq1, freq_params.center_freq2, + freq_params.bandwidth, freq_params.sec_channel_offset, + freq_params.ht_enabled ? " HT" : "", + freq_params.vht_enabled ? " VHT" : ""); + + ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class, + &freq_params); + if (ret) + return wpas_dbus_error_unknown_error( + message, "error processing TDLS channel switch"); + + return NULL; +} + +/* + * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "TDLSCancelChannelSwitch" method call of network + * interface. + */ +DBusMessage * +wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 peer[ETH_ALEN]; + DBusMessage *error_reply; + int ret; + + if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) + return error_reply; + + wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR, + MAC2STR(peer)); + + ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer); + if (ret) + return wpas_dbus_error_unknown_error( + message, "error canceling TDLS channel switch"); + + return NULL; +} + #endif /* CONFIG_TDLS */ @@ -2468,6 +2697,28 @@ dbus_bool_t wpas_dbus_getter_capabilities( goto nomem; } + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt", + &iter_dict_entry, + &iter_dict_val, + &iter_array) || + (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "aes-128-cmac")) || + (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "bip-gmac-128")) || + (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "bip-gmac-256")) || + (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "bip-cmac-256")) || + !wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + /***** key management */ if (res < 0) { const char *args[] = { @@ -2627,6 +2878,11 @@ dbus_bool_t wpas_dbus_getter_capabilities( !wpa_s->conf->p2p_disabled && !wpa_dbus_dict_string_array_add_element( &iter_array, "p2p")) || +#ifdef CONFIG_MESH + (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "mesh")) || +#endif /* CONFIG_MESH */ !wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, @@ -2837,6 +3093,27 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason( /** + * wpas_dbus_getter_auth_status_code - Get most recent auth status code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "AuthStatusCode" property. + */ +dbus_bool_t wpas_dbus_getter_auth_status_code( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t reason = wpa_s->auth_status_code; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &reason, error); +} + + +/** * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure @@ -2858,6 +3135,97 @@ dbus_bool_t wpas_dbus_getter_assoc_status_code( /** + * wpas_dbus_getter_roam_time - Get most recent roam time + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "RoamTime" property. + */ +dbus_bool_t wpas_dbus_getter_roam_time( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 + + wpa_s->roam_time.usec / 1000; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &roam_time, error); +} + + +/** + * wpas_dbus_getter_roam_complete - Get most recent roam success or failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "RoamComplete" property. + */ +dbus_bool_t wpas_dbus_getter_roam_complete( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &roam_complete, error); +} + + +/** + * wpas_dbus_getter_session_length - Get most recent BSS session length + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "SessionLength" property. + */ +dbus_bool_t wpas_dbus_getter_session_length( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 + + wpa_s->session_length.usec / 1000; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &session_length, error); +} + + +/** + * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request + * status code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "BSSTMStatus" property. + */ +dbus_bool_t wpas_dbus_getter_bss_tm_status( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_WNM + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status; +#else /* CONFIG_WNM */ + dbus_uint32_t bss_tm_status = 0; +#endif /* CONFIG_WNM */ + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &bss_tm_status, error); +} + + +/** * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure @@ -3086,10 +3454,8 @@ dbus_bool_t wpas_dbus_getter_ifname( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - const char *ifname = wpa_s->ifname; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &ifname, error); + return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error); } @@ -3107,7 +3473,6 @@ dbus_bool_t wpas_dbus_getter_driver( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - const char *driver; if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set", @@ -3117,9 +3482,8 @@ dbus_bool_t wpas_dbus_getter_driver( return FALSE; } - driver = wpa_s->driver->name; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &driver, error); + return wpas_dbus_string_property_getter(iter, wpa_s->driver->name, + error); } @@ -3232,10 +3596,9 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - const char *bridge_ifname = wpa_s->bridge_ifname; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &bridge_ifname, error); + return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname, + error); } @@ -3253,13 +3616,8 @@ dbus_bool_t wpas_dbus_getter_config_file( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - char *confname = ""; - - if (wpa_s->confname) - confname = wpa_s->confname; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &confname, error); + return wpas_dbus_string_property_getter(iter, wpa_s->confname, error); } @@ -3399,14 +3757,10 @@ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - const char *pkcs11_engine_path; - if (wpa_s->conf->pkcs11_engine_path == NULL) - pkcs11_engine_path = ""; - else - pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &pkcs11_engine_path, error); + return wpas_dbus_string_property_getter(iter, + wpa_s->conf->pkcs11_engine_path, + error); } @@ -3424,14 +3778,10 @@ dbus_bool_t wpas_dbus_getter_pkcs11_module_path( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - const char *pkcs11_module_path; - if (wpa_s->conf->pkcs11_module_path == NULL) - pkcs11_module_path = ""; - else - pkcs11_module_path = wpa_s->conf->pkcs11_module_path; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &pkcs11_module_path, error); + return wpas_dbus_string_property_getter(iter, + wpa_s->conf->pkcs11_module_path, + error); } @@ -3571,6 +3921,320 @@ dbus_bool_t wpas_dbus_setter_iface_global( } +/** + * wpas_dbus_getter_stas - Get connected stations for an interface + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: a list of stations + * + * Getter for "Stations" property. + */ +dbus_bool_t wpas_dbus_getter_stas( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct sta_info *sta = NULL; + char **paths = NULL; + unsigned int i = 0, num = 0; + dbus_bool_t success = FALSE; + + if (!wpa_s->dbus_new_path) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: no D-Bus interface", __func__); + return FALSE; + } + +#ifdef CONFIG_AP + if (wpa_s->ap_iface) { + struct hostapd_data *hapd; + + hapd = wpa_s->ap_iface->bss[0]; + sta = hapd->sta_list; + num = hapd->num_sta; + } +#endif /* CONFIG_AP */ + + paths = os_calloc(num, sizeof(char *)); + if (!paths) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + /* Loop through scan results and append each result's object path */ + for (; sta; sta = sta->next) { + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (!paths[i]) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + goto out; + } + /* Construct the object path for this BSS. */ + os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(sta->addr)); + } + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num, + error); + +out: + while (i) + os_free(paths[--i]); + os_free(paths); + return success; +} + + +/** + * wpas_dbus_getter_sta_address - Return the address of a connected station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Address" property. + */ +dbus_bool_t wpas_dbus_getter_sta_address( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + + sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta); + if (!sta) + return FALSE; + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + sta->addr, ETH_ALEN, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + +/** + * wpas_dbus_getter_sta_aid - Return the AID of a connected station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "AID" property. + */ +dbus_bool_t wpas_dbus_getter_sta_aid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + + sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta); + if (!sta) + return FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, + &sta->aid, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + +/** + * wpas_dbus_getter_sta_caps - Return the capabilities of a station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Capabilities" property. + */ +dbus_bool_t wpas_dbus_getter_sta_caps( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + + sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta); + if (!sta) + return FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, + &sta->capability, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + +/** + * wpas_dbus_getter_rx_packets - Return the received packets for a station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "RxPackets" property. + */ +dbus_bool_t wpas_dbus_getter_sta_rx_packets( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + struct hostap_sta_driver_data data; + struct hostapd_data *hapd; + + if (!args->wpa_s->ap_iface) + return FALSE; + + hapd = args->wpa_s->ap_iface->bss[0]; + sta = ap_get_sta(hapd, args->sta); + if (!sta) + return FALSE; + + if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) + return FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, + &data.rx_packets, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + +/** + * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "TxPackets" property. + */ +dbus_bool_t wpas_dbus_getter_sta_tx_packets( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + struct hostap_sta_driver_data data; + struct hostapd_data *hapd; + + if (!args->wpa_s->ap_iface) + return FALSE; + + hapd = args->wpa_s->ap_iface->bss[0]; + sta = ap_get_sta(hapd, args->sta); + if (!sta) + return FALSE; + + if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) + return FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, + &data.tx_packets, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + +/** + * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "TxBytes" property. + */ +dbus_bool_t wpas_dbus_getter_sta_tx_bytes( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + struct hostap_sta_driver_data data; + struct hostapd_data *hapd; + + if (!args->wpa_s->ap_iface) + return FALSE; + + hapd = args->wpa_s->ap_iface->bss[0]; + sta = ap_get_sta(hapd, args->sta); + if (!sta) + return FALSE; + + if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) + return FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, + &data.tx_bytes, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + +/** + * wpas_dbus_getter_rx_bytes - Return the received bytes for a station + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "RxBytes" property. + */ +dbus_bool_t wpas_dbus_getter_sta_rx_bytes( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ +#ifdef CONFIG_AP + struct sta_handler_args *args = user_data; + struct sta_info *sta; + struct hostap_sta_driver_data data; + struct hostapd_data *hapd; + + if (!args->wpa_s->ap_iface) + return FALSE; + + hapd = args->wpa_s->ap_iface->bss[0]; + sta = ap_get_sta(hapd, args->sta); + if (!sta) + return FALSE; + + if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) + return FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, + &data.rx_bytes, + error); +#else /* CONFIG_AP */ + return FALSE; +#endif /* CONFIG_AP */ +} + + static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, DBusError *error, const char *func_name) { @@ -3683,6 +4347,7 @@ dbus_bool_t wpas_dbus_getter_bss_mode( struct bss_handler_args *args = user_data; struct wpa_bss *res; const char *mode; + const u8 *mesh; res = get_bss_helper(args, error, __func__); if (!res) @@ -3696,9 +4361,15 @@ dbus_bool_t wpas_dbus_getter_bss_mode( case IEEE80211_CAP_DMG_AP: mode = "infrastructure"; break; + default: + mode = ""; + break; } } else { - if (res->caps & IEEE80211_CAP_IBSS) + mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID); + if (mesh) + mode = "mesh"; + else if (res->caps & IEEE80211_CAP_IBSS) mode = "ad-hoc"; else mode = "infrastructure"; @@ -3826,7 +4497,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( DBusMessageIter iter_dict, variant_iter; const char *group; const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ - const char *key_mgmt[9]; /* max 9 key managements may be supported */ + const char *key_mgmt[15]; /* max 15 key managements may be supported */ int n; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, @@ -3836,7 +4507,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) goto nomem; - /* KeyMgmt */ + /* + * KeyMgmt + * + * When adding a new entry here, please take care to extend key_mgmt[] + * and keep documentation in doc/dbus.doxygen up to date. + */ n = 0; if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK) key_mgmt[n++] = "wpa-psk"; @@ -3858,6 +4534,22 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) key_mgmt[n++] = "wpa-eap-suite-b-192"; #endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_FILS + if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) + key_mgmt[n++] = "wpa-fils-sha256"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) + key_mgmt[n++] = "wpa-fils-sha384"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) + key_mgmt[n++] = "wpa-ft-fils-sha256"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) + key_mgmt[n++] = "wpa-ft-fils-sha384"; +#endif /* CONFIG_FILS */ +#ifdef CONFIG_SAE + if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE) + key_mgmt[n++] = "sae"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE) + key_mgmt[n++] = "ft-sae"; +#endif /* CONFIG_SAE */ if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) key_mgmt[n++] = "wpa-none"; @@ -4534,3 +5226,100 @@ DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message, return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Not found"); } + + +#ifdef CONFIG_MESH + +/** + * wpas_dbus_getter_mesh_peers - Get connected mesh peers + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "MeshPeers" property. + */ +dbus_bool_t wpas_dbus_getter_mesh_peers( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct hostapd_data *hapd; + struct sta_info *sta; + DBusMessageIter variant_iter, array_iter; + int i; + DBusMessageIter inner_array_iter; + + if (!wpa_s->ifmsh) + return FALSE; + hapd = wpa_s->ifmsh->bss[0]; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &array_iter)) + return FALSE; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (!dbus_message_iter_open_container( + &array_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &inner_array_iter)) + return FALSE; + + for (i = 0; i < ETH_ALEN; i++) { + if (!dbus_message_iter_append_basic(&inner_array_iter, + DBUS_TYPE_BYTE, + &(sta->addr[i]))) + return FALSE; + } + + if (!dbus_message_iter_close_container( + &array_iter, &inner_array_iter)) + return FALSE; + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || + !dbus_message_iter_close_container(iter, &variant_iter)) + return FALSE; + + return TRUE; +} + + +/** + * wpas_dbus_getter_mesh_group - Get mesh group + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "MeshGroup" property. + */ +dbus_bool_t wpas_dbus_getter_mesh_group( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (!wpa_s->ifmsh || !ssid) + return FALSE; + + if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + (char *) ssid->ssid, + ssid->ssid_len, error)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: error constructing reply", __func__); + return FALSE; + } + + return TRUE; +} + +#endif /* CONFIG_MESH */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h index 1d6235d6f3e4..d922ce1b4189 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h @@ -22,6 +22,11 @@ struct bss_handler_args { unsigned int id; }; +struct sta_handler_args { + struct wpa_supplicant *wpa_s; + const u8 *sta; +}; + dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, const int type, const void *val, @@ -43,6 +48,10 @@ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, size_t array_len, DBusError *error); +dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter, + const void *val, + DBusError *error); + DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, struct wpa_global *global); @@ -70,6 +79,9 @@ DECLARE_ACCESSOR(wpas_dbus_setter_iface_global); DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message, struct wpa_supplicant *wpa_s); @@ -138,7 +150,12 @@ DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth); DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth); DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason); DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason); +DECLARE_ACCESSOR(wpas_dbus_getter_auth_status_code); DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code); +DECLARE_ACCESSOR(wpas_dbus_getter_roam_time); +DECLARE_ACCESSOR(wpas_dbus_getter_roam_complete); +DECLARE_ACCESSOR(wpas_dbus_getter_session_length); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_tm_status); DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age); DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age); DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count); @@ -159,6 +176,14 @@ DECLARE_ACCESSOR(wpas_dbus_getter_networks); DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path); DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path); DECLARE_ACCESSOR(wpas_dbus_getter_blobs); +DECLARE_ACCESSOR(wpas_dbus_getter_stas); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_address); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_packets); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_packets); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_bytes); +DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_bytes); DECLARE_ACCESSOR(wpas_dbus_getter_bss_bssid); DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid); DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy); @@ -186,6 +211,21 @@ DECLARE_ACCESSOR(wpas_dbus_getter_process_credentials); DECLARE_ACCESSOR(wpas_dbus_setter_process_credentials); DECLARE_ACCESSOR(wpas_dbus_getter_config_methods); DECLARE_ACCESSOR(wpas_dbus_setter_config_methods); +DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_name); +DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_name); +DECLARE_ACCESSOR(wpas_dbus_getter_wps_manufacturer); +DECLARE_ACCESSOR(wpas_dbus_setter_wps_manufacturer); +DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_name); +DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_name); +DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_number); +DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_number); +DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_serial_number); +DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_serial_number); +DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_device_type); +DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_device_type); + +DECLARE_ACCESSOR(wpas_dbus_getter_mesh_peers); +DECLARE_ACCESSOR(wpas_dbus_getter_mesh_group); DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, struct wpa_supplicant *wpa_s); @@ -195,6 +235,12 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * +wpas_dbus_handler_tdls_channel_switch(DBusMessage *message, + struct wpa_supplicant *wpa_s); +DBusMessage * +wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message, + struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, struct wpa_supplicant *wpa_s); diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 73b9e20c20b0..8cdd885644af 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -28,6 +28,18 @@ #include "../p2p_supplicant.h" #include "../wifi_display.h" + +static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry) +{ + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE || + entry.array_len != 4) + return 0; + + return 1; +} + + /** * Parses out the mac address from the peer object path. * @peer_path - object path of the form @@ -78,6 +90,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, int num_req_dev_types = 0; unsigned int i; u8 *req_dev_types = NULL; + unsigned int freq = 0; dbus_message_iter_init(message, &iter); entry.key = NULL; @@ -122,6 +135,10 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, type = P2P_FIND_PROGRESSIVE; else goto error_clear; + } else if (os_strcmp(entry.key, "freq") == 0 && + (entry.type == DBUS_TYPE_INT32 || + entry.type == DBUS_TYPE_UINT32)) { + freq = entry.uint32_value; } else goto error_clear; wpa_dbus_dict_entry_clear(&entry); @@ -129,8 +146,11 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, wpa_s = wpa_s->global->p2p_init_wpa_s; - wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types, - NULL, 0, 0, NULL, 0); + if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, + req_dev_types, NULL, 0, 0, NULL, freq)) + reply = wpas_dbus_error_unknown_error( + message, "Could not start P2P find"); + os_free(req_dev_types); return reply; @@ -364,14 +384,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, goto inv_args; if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0, - 0, 0, NULL, 0, 0)) { + 0, 0, 0, NULL, 0, 0)) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); goto out; } } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0, - 0)) + 0, 0)) goto inv_args; out: @@ -485,6 +505,7 @@ DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message, wpa_s = wpa_s->global->p2p_init_wpa_s; + wpas_p2p_stop_find(wpa_s); os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); wpa_s->force_long_sd = 0; p2p_flush(wpa_s->global->p2p); @@ -512,6 +533,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, int new_pin; char *err_msg = NULL; char *iface = NULL; + int ret; if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) return reply; @@ -583,13 +605,19 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, 0, join, authorize_only, - go_intent, freq, 0, -1, 0, 0, 0, 0, NULL, 0); + go_intent, freq, 0, -1, 0, 0, 0, 0, 0, + NULL, 0); if (new_pin >= 0) { char npin[9]; char *generated_pin; - os_snprintf(npin, sizeof(npin), "%08d", new_pin); + ret = os_snprintf(npin, sizeof(npin), "%08d", new_pin); + if (os_snprintf_error(sizeof(npin), ret)) { + reply = wpas_dbus_error_unknown_error(message, + "invalid PIN"); + goto out; + } generated_pin = npin; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_STRING, @@ -735,7 +763,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, goto err; if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0, - 0) < 0) { + 0, 0) < 0) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); @@ -867,6 +895,35 @@ dbus_bool_t wpas_dbus_getter_p2p_device_config( goto err_no_mem; } + /* GO IP address */ + if (WPA_GET_BE32(wpa_s->conf->ip_addr_go) && + !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo", + (char *) wpa_s->conf->ip_addr_go, + 4)) + goto err_no_mem; + + /* IP address mask */ + if (WPA_GET_BE32(wpa_s->conf->ip_addr_mask) && + !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask", + (char *) wpa_s->conf->ip_addr_mask, + 4)) + goto err_no_mem; + + /* IP address start */ + if (WPA_GET_BE32(wpa_s->conf->ip_addr_start) && + !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrStart", + (char *) + wpa_s->conf->ip_addr_start, + 4)) + goto err_no_mem; + + /* IP address end */ + if (WPA_GET_BE32(wpa_s->conf->ip_addr_end) && + !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrEnd", + (char *) wpa_s->conf->ip_addr_end, + 4)) + goto err_no_mem; + /* Vendor Extensions */ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { if (wpa_s->conf->wps_vendor_ext[i] == NULL) @@ -1051,6 +1108,26 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config( wpa_s->conf->p2p_intra_bss = entry.bool_value; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_INTRA_BSS; + } else if (os_strcmp(entry.key, "IpAddrGo") == 0) { + if (!wpas_dbus_validate_dbus_ipaddr(entry)) + goto error; + os_memcpy(wpa_s->conf->ip_addr_go, + entry.bytearray_value, 4); + } else if (os_strcmp(entry.key, "IpAddrMask") == 0) { + if (!wpas_dbus_validate_dbus_ipaddr(entry)) + goto error; + os_memcpy(wpa_s->conf->ip_addr_mask, + entry.bytearray_value, 4); + } else if (os_strcmp(entry.key, "IpAddrStart") == 0) { + if (!wpas_dbus_validate_dbus_ipaddr(entry)) + goto error; + os_memcpy(wpa_s->conf->ip_addr_start, + entry.bytearray_value, 4); + } else if (os_strcmp(entry.key, "IpAddrEnd") == 0) { + if (!wpas_dbus_validate_dbus_ipaddr(entry)) + goto error; + os_memcpy(wpa_s->conf->ip_addr_end, + entry.bytearray_value, 4); } else if (os_strcmp(entry.key, "GroupIdle") == 0 && entry.type == DBUS_TYPE_UINT32) wpa_s->conf->p2p_group_idle = entry.uint32_value; @@ -1841,6 +1918,30 @@ out: return success; } +dbus_bool_t wpas_dbus_getter_p2p_peer_vsie( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (!info) { + dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); + return FALSE; + } + + if (!info->vendor_elems) + return wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_BYTE, + NULL, 0, error); + + return wpas_dbus_simple_array_property_getter( + iter, DBUS_TYPE_BYTE, (char *) info->vendor_elems->buf, + info->vendor_elems->used, error); +} + /** * wpas_dbus_getter_persistent_groups - Get array of persistent group objects @@ -2286,19 +2387,12 @@ dbus_bool_t wpas_dbus_getter_p2p_group_passphrase( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - char *p_pass; struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid == NULL) return FALSE; - p_pass = ssid->passphrase; - if (!p_pass) - p_pass = ""; - - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &p_pass, error); - + return wpas_dbus_string_property_getter(iter, ssid->passphrase, error); } @@ -2599,7 +2693,7 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service( if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; - if (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; @@ -2611,26 +2705,27 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service( bonjour = 1; else goto error_clear; - wpa_dbus_dict_entry_clear(&entry); - } - } - if (upnp == 1) { - while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) - goto error; - if (os_strcmp(entry.key, "version") == 0 && - entry.type == DBUS_TYPE_INT32) - version = entry.uint32_value; - else if (os_strcmp(entry.key, "service") == 0 && - entry.type == DBUS_TYPE_STRING) { - os_free(service); - service = os_strdup(entry.str_value); - } else + } else if (os_strcmp(entry.key, "version") == 0 && + entry.type == DBUS_TYPE_INT32) { + version = entry.uint32_value; + } else if (os_strcmp(entry.key, "service") == 0 && + entry.type == DBUS_TYPE_STRING) { + os_free(service); + service = os_strdup(entry.str_value); + } else if (os_strcmp(entry.key, "query") == 0) { + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE) goto error_clear; - - wpa_dbus_dict_entry_clear(&entry); + wpabuf_free(query); + query = wpabuf_alloc_copy(entry.bytearray_value, + entry.array_len); + } else { + goto error_clear; } + wpa_dbus_dict_entry_clear(&entry); + } + if (upnp == 1) { if (version <= 0 || service == NULL) goto error; @@ -2638,24 +2733,6 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service( if (ret != 0) goto error; } else if (bonjour == 1) { - while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) - goto error; - - if (os_strcmp(entry.key, "query") == 0) { - if (entry.type != DBUS_TYPE_ARRAY || - entry.array_type != DBUS_TYPE_BYTE) - goto error_clear; - wpabuf_free(query); - query = wpabuf_alloc_copy( - entry.bytearray_value, - entry.array_len); - } else - goto error_clear; - - wpa_dbus_dict_entry_clear(&entry); - } - if (query == NULL) goto error; diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h index c4c02615dbc3..b3c45c11012c 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h @@ -114,6 +114,7 @@ DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vendor_extension); DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_ies); DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_address); DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_groups); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vsie); /* * P2P Group properties diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c index f16e2290c7ed..1594dafc7bb5 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c @@ -286,10 +286,14 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, ret = wpas_wps_start_pin(wpa_s, params.bssid, params.pin, 0, DEV_PW_DEFAULT); - if (ret > 0) - os_snprintf(npin, sizeof(npin), "%08d", ret); + if (ret > 0) { + ret = os_snprintf(npin, sizeof(npin), "%08d", ret); + if (os_snprintf_error(sizeof(npin), ret)) + return wpas_dbus_error_unknown_error( + message, "invalid PIN"); + } } else { - ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0); + ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0, 0); } if (ret < 0) { @@ -412,12 +416,10 @@ dbus_bool_t wpas_dbus_getter_config_methods( DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - char *methods = wpa_s->conf->config_methods; - if (methods == NULL) - methods = ""; - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, - &methods, error); + return wpas_dbus_string_property_getter(iter, + wpa_s->conf->config_methods, + error); } @@ -454,3 +456,349 @@ dbus_bool_t wpas_dbus_setter_config_methods( return TRUE; } + + +/** + * wpas_dbus_getter_wps_device_name - Get current WPS device name + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DeviceName" property. + */ +dbus_bool_t wpas_dbus_getter_wps_device_name( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + return wpas_dbus_string_property_getter(iter, wpa_s->conf->device_name, + error); +} + + +/** + * wpas_dbus_setter_wps_device_name - Set current WPS device name + * @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 "DeviceName" property. + */ +dbus_bool_t wpas_dbus_setter_wps_device_name( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char *methods, *devname; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &methods)) + return FALSE; + + if (os_strlen(methods) > WPS_DEV_NAME_MAX_LEN) + return FALSE; + + devname = os_strdup(methods); + if (!devname) + return FALSE; + + os_free(wpa_s->conf->device_name); + wpa_s->conf->device_name = devname; + wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_NAME; + wpa_supplicant_update_config(wpa_s); + + return TRUE; +} + + +/** + * wpas_dbus_getter_wps_manufacturer - Get current manufacturer name + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Manufacturer" property. + */ +dbus_bool_t wpas_dbus_getter_wps_manufacturer( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + return wpas_dbus_string_property_getter(iter, wpa_s->conf->manufacturer, + error); +} + + +/** + * wpas_dbus_setter_wps_manufacturer - Set current manufacturer name + * @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 "Manufacturer" property. + */ +dbus_bool_t wpas_dbus_setter_wps_manufacturer( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char *methods, *manufacturer; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &methods)) + return FALSE; + + if (os_strlen(methods) > WPS_MANUFACTURER_MAX_LEN) + return FALSE; + + manufacturer = os_strdup(methods); + if (!manufacturer) + return FALSE; + + os_free(wpa_s->conf->manufacturer); + wpa_s->conf->manufacturer = manufacturer; + wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING; + wpa_supplicant_update_config(wpa_s); + + return TRUE; +} + + +/** + * wpas_dbus_getter_wps_device_model_name - Get current device model name + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "ModelName" property. + */ +dbus_bool_t wpas_dbus_getter_wps_device_model_name( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_name, + error); +} + + +/** + * wpas_dbus_setter_wps_device_model_name - Set current device model name + * @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 "ModelName" property. + */ +dbus_bool_t wpas_dbus_setter_wps_device_model_name( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char *methods, *model_name; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &methods)) + return FALSE; + + if (os_strlen(methods) > WPS_MODEL_NAME_MAX_LEN) + return FALSE; + + model_name = os_strdup(methods); + if (!model_name) + return FALSE; + os_free(wpa_s->conf->model_name); + wpa_s->conf->model_name = model_name; + wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING; + wpa_supplicant_update_config(wpa_s); + + return TRUE; +} + + +/** + * wpas_dbus_getter_wps_device_model_number - Get current device model number + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "ModelNumber" property. + */ +dbus_bool_t wpas_dbus_getter_wps_device_model_number( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_number, + error); +} + + +/** + * wpas_dbus_setter_wps_device_model_number - Set current device model number + * @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 "ModelNumber" property. + */ +dbus_bool_t wpas_dbus_setter_wps_device_model_number( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char *methods, *model_number; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &methods)) + return FALSE; + + if (os_strlen(methods) > WPS_MODEL_NUMBER_MAX_LEN) + return FALSE; + + model_number = os_strdup(methods); + if (!model_number) + return FALSE; + + os_free(wpa_s->conf->model_number); + wpa_s->conf->model_number = model_number; + wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING; + wpa_supplicant_update_config(wpa_s); + + return TRUE; +} + + +/** + * wpas_dbus_getter_wps_device_serial_number - Get current device serial number + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "SerialNumber" property. + */ +dbus_bool_t wpas_dbus_getter_wps_device_serial_number( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + return wpas_dbus_string_property_getter(iter, + wpa_s->conf->serial_number, + error); +} + + +/** + * wpas_dbus_setter_wps_device_serial_number - Set current device serial number + * @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 "SerialNumber" property. + */ +dbus_bool_t wpas_dbus_setter_wps_device_serial_number( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char *methods, *serial_number; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &methods)) + return FALSE; + + if (os_strlen(methods) > WPS_SERIAL_NUMBER_MAX_LEN) + return FALSE; + + serial_number = os_strdup(methods); + if (!serial_number) + return FALSE; + os_free(wpa_s->conf->serial_number); + wpa_s->conf->serial_number = serial_number; + wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING; + wpa_supplicant_update_config(wpa_s); + + return TRUE; +} + + +/** + * wpas_dbus_getter_wps_device_device_type - Get current device type + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DeviceType" property. + */ +dbus_bool_t wpas_dbus_getter_wps_device_device_type( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + (char *) + wpa_s->conf->device_type, + WPS_DEV_TYPE_LEN, error)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: error constructing reply", __func__); + return FALSE; + } + + return TRUE; +} + + +/** + * wpas_dbus_setter_wps_device_device_type - Set current device type + * @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 "DeviceType" property. + */ +dbus_bool_t wpas_dbus_setter_wps_device_device_type( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + u8 *dev_type; + int dev_len; + DBusMessageIter variant, array_iter; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(iter, &variant); + if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY) + return FALSE; + + dbus_message_iter_recurse(&variant, &array_iter); + dbus_message_iter_get_fixed_array(&array_iter, &dev_type, &dev_len); + + if (dev_len != WPS_DEV_TYPE_LEN) + return FALSE; + + os_memcpy(wpa_s->conf->device_type, dev_type, WPS_DEV_TYPE_LEN); + wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_TYPE; + wpa_supplicant_update_config(wpa_s); + + return TRUE; +} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old.c deleted file mode 100644 index 88227af7c03b..000000000000 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_old.c +++ /dev/null @@ -1,745 +0,0 @@ -/* - * WPA Supplicant / dbus-based control interface - * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include <dbus/dbus.h> - -#include "common.h" -#include "eloop.h" -#include "wps/wps.h" -#include "../config.h" -#include "../wpa_supplicant_i.h" -#include "../bss.h" -#include "dbus_old.h" -#include "dbus_old_handlers.h" -#include "dbus_common_i.h" - - -/** - * wpas_dbus_decompose_object_path - Decompose an interface object path into parts - * @path: The dbus object path - * @network: (out) the configured network this object path refers to, if any - * @bssid: (out) the scanned bssid this object path refers to, if any - * Returns: The object path of the network interface this path refers to - * - * For a given object path, decomposes the object path into object id, network, - * and BSSID parts, if those parts exist. - */ -char * wpas_dbus_decompose_object_path(const char *path, char **network, - char **bssid) -{ - const unsigned int dev_path_prefix_len = - strlen(WPAS_DBUS_PATH_INTERFACES "/"); - char *obj_path_only; - char *next_sep; - - /* Be a bit paranoid about path */ - if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", - dev_path_prefix_len)) - return NULL; - - /* Ensure there's something at the end of the path */ - if ((path + dev_path_prefix_len)[0] == '\0') - return NULL; - - obj_path_only = os_strdup(path); - if (obj_path_only == NULL) - return NULL; - - next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); - if (next_sep != NULL) { - const char *net_part = strstr(next_sep, - WPAS_DBUS_NETWORKS_PART "/"); - const char *bssid_part = strstr(next_sep, - WPAS_DBUS_BSSIDS_PART "/"); - - if (network && net_part) { - /* Deal with a request for a configured network */ - const char *net_name = net_part + - strlen(WPAS_DBUS_NETWORKS_PART "/"); - *network = NULL; - if (strlen(net_name)) - *network = os_strdup(net_name); - } else if (bssid && bssid_part) { - /* Deal with a request for a scanned BSSID */ - const char *bssid_name = bssid_part + - strlen(WPAS_DBUS_BSSIDS_PART "/"); - if (strlen(bssid_name)) - *bssid = os_strdup(bssid_name); - else - *bssid = NULL; - } - - /* Cut off interface object path before "/" */ - *next_sep = '\0'; - } - - return obj_path_only; -} - - -/** - * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message - * @message: Pointer to incoming dbus message this error refers to - * Returns: A dbus error message - * - * Convenience function to create and return an invalid interface error - */ -DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) -{ - return dbus_message_new_error( - message, WPAS_ERROR_INVALID_IFACE, - "wpa_supplicant knows nothing about this interface."); -} - - -/** - * wpas_dbus_new_invalid_network_error - Return a new invalid network error message - * @message: Pointer to incoming dbus message this error refers to - * Returns: a dbus error message - * - * Convenience function to create and return an invalid network error - */ -DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) -{ - return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, - "The requested network does not exist."); -} - - -/** - * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message - * @message: Pointer to incoming dbus message this error refers to - * Returns: a dbus error message - * - * Convenience function to create and return an invalid bssid error - */ -static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) -{ - return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, - "The BSSID requested was invalid."); -} - - -/** - * wpas_dispatch_network_method - dispatch messages for configured networks - * @message: the incoming dbus message - * @wpa_s: a network interface's data - * @network_id: id of the configured network we're interested in - * Returns: a reply dbus message, or a dbus error message - * - * This function dispatches all incoming dbus messages for configured networks. - */ -static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, - struct wpa_supplicant *wpa_s, - int network_id) -{ - DBusMessage *reply = NULL; - const char *method = dbus_message_get_member(message); - struct wpa_ssid *ssid; - - ssid = wpa_config_get_network(wpa_s->conf, network_id); - if (ssid == NULL) - return wpas_dbus_new_invalid_network_error(message); - - if (!strcmp(method, "set")) - reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); - else if (!strcmp(method, "enable")) - reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); - else if (!strcmp(method, "disable")) - reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); - - return reply; -} - - -/** - * wpas_dispatch_bssid_method - dispatch messages for scanned networks - * @message: the incoming dbus message - * @wpa_s: a network interface's data - * @bssid: bssid of the scanned network we're interested in - * Returns: a reply dbus message, or a dbus error message - * - * This function dispatches all incoming dbus messages for scanned networks. - */ -static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, - struct wpa_supplicant *wpa_s, - const char *bssid_txt) -{ - u8 bssid[ETH_ALEN]; - struct wpa_bss *bss; - - if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) - return wpas_dbus_new_invalid_bssid_error(message); - - bss = wpa_bss_get_bssid(wpa_s, bssid); - if (bss == NULL) - return wpas_dbus_new_invalid_bssid_error(message); - - /* Dispatch the method call against the scanned bssid */ - if (os_strcmp(dbus_message_get_member(message), "properties") == 0) - return wpas_dbus_bssid_properties(message, wpa_s, bss); - - return NULL; -} - - -/** - * wpas_iface_message_handler - Dispatch messages for interfaces or networks - * @connection: Connection to the system message bus - * @message: An incoming dbus message - * @user_data: A pointer to a dbus control interface data structure - * Returns: Whether or not the message was handled - * - * This function dispatches all incoming dbus messages for network interfaces, - * or objects owned by them, such as scanned BSSIDs and configured networks. - */ -static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - struct wpa_supplicant *wpa_s = user_data; - const char *method = dbus_message_get_member(message); - const char *path = dbus_message_get_path(message); - const char *msg_interface = dbus_message_get_interface(message); - char *iface_obj_path = NULL; - char *network = NULL; - char *bssid = NULL; - DBusMessage *reply = NULL; - - /* Caller must specify a message interface */ - if (!msg_interface) - goto out; - - wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]", - msg_interface, method, path, - dbus_message_get_signature(message)); - - iface_obj_path = wpas_dbus_decompose_object_path(path, &network, - &bssid); - if (iface_obj_path == NULL) { - reply = wpas_dbus_new_invalid_iface_error(message); - goto out; - } - - /* Make sure the message's object path actually refers to the - * wpa_supplicant structure it's supposed to (which is wpa_s) - */ - if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, - iface_obj_path) != wpa_s) { - reply = wpas_dbus_new_invalid_iface_error(message); - goto out; - } - - if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { - /* A method for one of this interface's configured networks */ - int nid = strtoul(network, NULL, 10); - - if (errno != EINVAL) - reply = wpas_dispatch_network_method(message, wpa_s, - nid); - else - reply = wpas_dbus_new_invalid_network_error(message); - } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { - /* A method for one of this interface's scanned BSSIDs */ - reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); - } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { - /* A method for an interface only. */ - if (!strcmp(method, "scan")) - reply = wpas_dbus_iface_scan(message, wpa_s); - else if (!strcmp(method, "scanResults")) - reply = wpas_dbus_iface_scan_results(message, wpa_s); - else if (!strcmp(method, "addNetwork")) - reply = wpas_dbus_iface_add_network(message, wpa_s); - else if (!strcmp(method, "removeNetwork")) - reply = wpas_dbus_iface_remove_network(message, wpa_s); - else if (!strcmp(method, "selectNetwork")) - reply = wpas_dbus_iface_select_network(message, wpa_s); - else if (!strcmp(method, "capabilities")) - reply = wpas_dbus_iface_capabilities(message, wpa_s); - else if (!strcmp(method, "disconnect")) - reply = wpas_dbus_iface_disconnect(message, wpa_s); - else if (!strcmp(method, "setAPScan")) - reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); - else if (!strcmp(method, "setSmartcardModules")) - reply = wpas_dbus_iface_set_smartcard_modules(message, - wpa_s); - else if (!strcmp(method, "state")) - reply = wpas_dbus_iface_get_state(message, wpa_s); - else if (!strcmp(method, "scanning")) - reply = wpas_dbus_iface_get_scanning(message, wpa_s); -#ifndef CONFIG_NO_CONFIG_BLOBS - else if (!strcmp(method, "setBlobs")) - reply = wpas_dbus_iface_set_blobs(message, wpa_s); - else if (!strcmp(method, "removeBlobs")) - reply = wpas_dbus_iface_remove_blobs(message, wpa_s); -#endif /* CONFIG_NO_CONFIG_BLOBS */ -#ifdef CONFIG_WPS - else if (os_strcmp(method, "wpsPbc") == 0) - reply = wpas_dbus_iface_wps_pbc(message, wpa_s); - else if (os_strcmp(method, "wpsPin") == 0) - reply = wpas_dbus_iface_wps_pin(message, wpa_s); - else if (os_strcmp(method, "wpsReg") == 0) - reply = wpas_dbus_iface_wps_reg(message, wpa_s); -#endif /* CONFIG_WPS */ - else if (os_strcmp(method, "flush") == 0) - reply = wpas_dbus_iface_flush(message, wpa_s); - } - - /* If the message was handled, send back the reply */ -out: - if (reply) { - if (!dbus_message_get_no_reply(message)) - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - } - - os_free(iface_obj_path); - os_free(network); - os_free(bssid); - return reply ? DBUS_HANDLER_RESULT_HANDLED : - DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - - -/** - * wpas_message_handler - dispatch incoming dbus messages - * @connection: connection to the system message bus - * @message: an incoming dbus message - * @user_data: a pointer to a dbus control interface data structure - * Returns: whether or not the message was handled - * - * This function dispatches all incoming dbus messages to the correct - * handlers, depending on what the message's target object path is, - * and what the method call is. - */ -static DBusHandlerResult wpas_message_handler(DBusConnection *connection, - DBusMessage *message, void *user_data) -{ - struct wpas_dbus_priv *ctrl_iface = user_data; - const char *method; - const char *path; - const char *msg_interface; - DBusMessage *reply = NULL; - - method = dbus_message_get_member(message); - path = dbus_message_get_path(message); - msg_interface = dbus_message_get_interface(message); - if (!method || !path || !ctrl_iface || !msg_interface) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]", - msg_interface, method, path, - dbus_message_get_signature(message)); - - /* Validate the method interface */ - if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (!strcmp(path, WPAS_DBUS_PATH)) { - /* dispatch methods against our global dbus interface here */ - if (!strcmp(method, "addInterface")) { - reply = wpas_dbus_global_add_interface( - message, ctrl_iface->global); - } else if (!strcmp(method, "removeInterface")) { - reply = wpas_dbus_global_remove_interface( - message, ctrl_iface->global); - } else if (!strcmp(method, "getInterface")) { - reply = wpas_dbus_global_get_interface( - message, ctrl_iface->global); - } else if (!strcmp(method, "setDebugParams")) { - reply = wpas_dbus_global_set_debugparams( - message, ctrl_iface->global); - } - } - - /* If the message was handled, send back the reply */ - if (reply) { - if (!dbus_message_get_no_reply(message)) - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - } - - return reply ? DBUS_HANDLER_RESULT_HANDLED : - DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - - -/** - * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal - * @wpa_s: %wpa_supplicant network interface data - * Returns: 0 on success, -1 on failure - * - * Notify listeners that this interface has updated scan results. - */ -void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) -{ - struct wpas_dbus_priv *iface = wpa_s->global->dbus; - DBusMessage *_signal; - - /* Do nothing if the control interface is not turned on */ - if (iface == NULL || !wpa_s->dbus_path) - return; - - _signal = dbus_message_new_signal(wpa_s->dbus_path, - WPAS_DBUS_IFACE_INTERFACE, - "ScanResultsAvailable"); - if (_signal == NULL) { - wpa_printf(MSG_ERROR, - "dbus: Not enough memory to send scan results signal"); - return; - } - dbus_connection_send(iface->con, _signal, NULL); - dbus_message_unref(_signal); -} - - -/** - * wpa_supplicant_dbus_notify_state_change - Send a state change signal - * @wpa_s: %wpa_supplicant network interface data - * @new_state: new state wpa_supplicant is entering - * @old_state: old state wpa_supplicant is leaving - * Returns: 0 on success, -1 on failure - * - * Notify listeners that wpa_supplicant has changed state - */ -void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, - enum wpa_states new_state, - enum wpa_states old_state) -{ - struct wpas_dbus_priv *iface; - DBusMessage *_signal = NULL; - const char *new_state_str, *old_state_str; - - if (wpa_s->dbus_path == NULL) - return; /* Skip signal since D-Bus setup is not yet ready */ - - /* Do nothing if the control interface is not turned on */ - if (wpa_s->global == NULL) - return; - iface = wpa_s->global->dbus; - if (iface == NULL) - return; - - /* Only send signal if state really changed */ - if (new_state == old_state) - return; - - _signal = dbus_message_new_signal(wpa_s->dbus_path, - WPAS_DBUS_IFACE_INTERFACE, - "StateChange"); - if (_signal == NULL) { - wpa_printf(MSG_ERROR, - "dbus: %s: could not create dbus signal; likely out of memory", - __func__); - return; - } - - new_state_str = wpa_supplicant_state_txt(new_state); - old_state_str = wpa_supplicant_state_txt(old_state); - - if (!dbus_message_append_args(_signal, - DBUS_TYPE_STRING, &new_state_str, - DBUS_TYPE_STRING, &old_state_str, - DBUS_TYPE_INVALID)) { - wpa_printf(MSG_ERROR, - "dbus: %s: Not enough memory to construct state change signal", - __func__); - goto out; - } - - dbus_connection_send(iface->con, _signal, NULL); - -out: - dbus_message_unref(_signal); -} - - -/** - * wpa_supplicant_dbus_notify_scanning - send scanning status - * @wpa_s: %wpa_supplicant network interface data - * Returns: 0 on success, -1 on failure - * - * Notify listeners of interface scanning state changes - */ -void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) -{ - struct wpas_dbus_priv *iface = wpa_s->global->dbus; - DBusMessage *_signal; - dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; - - /* Do nothing if the control interface is not turned on */ - if (iface == NULL || !wpa_s->dbus_path) - return; - - _signal = dbus_message_new_signal(wpa_s->dbus_path, - WPAS_DBUS_IFACE_INTERFACE, - "Scanning"); - if (_signal == NULL) { - wpa_printf(MSG_ERROR, - "dbus: Not enough memory to send scan results signal"); - return; - } - - if (dbus_message_append_args(_signal, - DBUS_TYPE_BOOLEAN, &scanning, - DBUS_TYPE_INVALID)) { - dbus_connection_send(iface->con, _signal, NULL); - } else { - wpa_printf(MSG_ERROR, - "dbus: Not enough memory to construct signal"); - } - dbus_message_unref(_signal); -} - - -#ifdef CONFIG_WPS -void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, - const struct wps_credential *cred) -{ - struct wpas_dbus_priv *iface; - DBusMessage *_signal = NULL; - - /* Do nothing if the control interface is not turned on */ - if (wpa_s->global == NULL) - return; - iface = wpa_s->global->dbus; - if (iface == NULL || !wpa_s->dbus_path) - return; - - _signal = dbus_message_new_signal(wpa_s->dbus_path, - WPAS_DBUS_IFACE_INTERFACE, - "WpsCred"); - if (_signal == NULL) { - wpa_printf(MSG_ERROR, - "dbus: %s: Could not create dbus signal; likely out of memory", - __func__); - return; - } - - if (!dbus_message_append_args(_signal, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &cred->cred_attr, cred->cred_attr_len, - DBUS_TYPE_INVALID)) { - wpa_printf(MSG_ERROR, - "dbus: %s: Not enough memory to construct signal", - __func__); - goto out; - } - - dbus_connection_send(iface->con, _signal, NULL); - -out: - dbus_message_unref(_signal); -} -#else /* CONFIG_WPS */ -void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, - const struct wps_credential *cred) -{ -} -#endif /* CONFIG_WPS */ - -void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, - int depth, const char *subject, - const char *cert_hash, - const struct wpabuf *cert) -{ - struct wpas_dbus_priv *iface; - DBusMessage *_signal = NULL; - const char *hash; - const char *cert_hex; - int cert_hex_len; - - /* Do nothing if the control interface is not turned on */ - if (wpa_s->global == NULL) - return; - iface = wpa_s->global->dbus; - if (iface == NULL || !wpa_s->dbus_path) - return; - - _signal = dbus_message_new_signal(wpa_s->dbus_path, - WPAS_DBUS_IFACE_INTERFACE, - "Certification"); - if (_signal == NULL) { - wpa_printf(MSG_ERROR, - "dbus: %s: Could not create dbus signal; likely out of memory", - __func__); - return; - } - - hash = cert_hash ? cert_hash : ""; - cert_hex = cert ? wpabuf_head(cert) : ""; - cert_hex_len = cert ? wpabuf_len(cert) : 0; - - if (!dbus_message_append_args(_signal, - DBUS_TYPE_INT32, &depth, - DBUS_TYPE_STRING, &subject, - DBUS_TYPE_STRING, &hash, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &cert_hex, cert_hex_len, - DBUS_TYPE_INVALID)) { - wpa_printf(MSG_ERROR, - "dbus: %s: Not enough memory to construct signal", - __func__); - goto out; - } - - dbus_connection_send(iface->con, _signal, NULL); - -out: - dbus_message_unref(_signal); - -} - - -/** - * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface - * @global: Pointer to global data from wpa_supplicant_init() - * Returns: 0 on success, -1 on failure - * - * Initialize the dbus control interface and start receiving commands from - * external programs over the bus. - */ -int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface) -{ - DBusError error; - int ret = -1; - DBusObjectPathVTable wpas_vtable = { - NULL, &wpas_message_handler, NULL, NULL, NULL, NULL - }; - - /* Register the message handler for the global dbus interface */ - if (!dbus_connection_register_object_path(iface->con, - WPAS_DBUS_PATH, &wpas_vtable, - iface)) { - wpa_printf(MSG_ERROR, "dbus: Could not set up message handler"); - return -1; - } - - /* Register our service with the message bus */ - dbus_error_init(&error); - switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, - 0, &error)) { - case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: - ret = 0; - break; - case DBUS_REQUEST_NAME_REPLY_EXISTS: - case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: - case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: - wpa_printf(MSG_ERROR, - "dbus: Could not request service name: already registered"); - break; - default: - wpa_printf(MSG_ERROR, - "dbus: Could not request service name: %s %s", - error.name, error.message); - break; - } - dbus_error_free(&error); - - if (ret != 0) - return -1; - - wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE - "'."); - - return 0; -} - - -/** - * wpas_dbus_register_new_iface - Register a new interface with dbus - * @wpa_s: %wpa_supplicant interface description structure to register - * Returns: 0 on success, -1 on error - * - * Registers a new interface with dbus and assigns it a dbus object path. - */ -int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) -{ - struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; - DBusConnection * con; - u32 next; - DBusObjectPathVTable vtable = { - NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL - }; - - /* Do nothing if the control interface is not turned on */ - if (ctrl_iface == NULL) - return 0; - - con = ctrl_iface->con; - next = ctrl_iface->next_objid++; - - /* Create and set the interface's object path */ - wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); - if (wpa_s->dbus_path == NULL) - return -1; - os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX, - WPAS_DBUS_PATH_INTERFACES "/%u", - next); - - /* Register the message handler for the interface functions */ - if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable, - wpa_s)) { - wpa_printf(MSG_ERROR, - "dbus: Could not set up message handler for interface %s", - wpa_s->ifname); - return -1; - } - - return 0; -} - - -/** - * wpas_dbus_unregister_iface - Unregister an interface from dbus - * @wpa_s: wpa_supplicant interface structure - * Returns: 0 on success, -1 on failure - * - * Unregisters the interface with dbus - */ -int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) -{ - struct wpas_dbus_priv *ctrl_iface; - DBusConnection *con; - - /* Do nothing if the control interface is not turned on */ - if (wpa_s == NULL || wpa_s->global == NULL) - return 0; - ctrl_iface = wpa_s->global->dbus; - if (ctrl_iface == NULL || wpa_s->dbus_path == NULL) - return 0; - - con = ctrl_iface->con; - if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path)) - return -1; - - os_free(wpa_s->dbus_path); - wpa_s->dbus_path = NULL; - - return 0; -} - - -/** - * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface - * @global: Pointer to global data from wpa_supplicant_init() - * @path: Pointer to a dbus object path representing an interface - * Returns: Pointer to the interface or %NULL if not found - */ -struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( - struct wpa_global *global, const char *path) -{ - struct wpa_supplicant *wpa_s; - - for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { - if (wpa_s->dbus_path && strcmp(wpa_s->dbus_path, path) == 0) - return wpa_s; - } - return NULL; -} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old.h deleted file mode 100644 index 451a9f827aa9..000000000000 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_old.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * WPA Supplicant / dbus-based control interface - * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef CTRL_IFACE_DBUS_H -#define CTRL_IFACE_DBUS_H - -struct wps_credential; - -#ifdef CONFIG_CTRL_IFACE_DBUS - -#define WPAS_DBUS_OBJECT_PATH_MAX 150 - -#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant" -#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant" -#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant" - -#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces" -#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" - -#define WPAS_DBUS_NETWORKS_PART "Networks" -#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" - -#define WPAS_DBUS_BSSIDS_PART "BSSIDs" -#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID" - - -/* Errors */ -#define WPAS_ERROR_INVALID_NETWORK \ - WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork" -#define WPAS_ERROR_INVALID_BSSID \ - WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID" - -#define WPAS_ERROR_INVALID_OPTS \ - WPAS_DBUS_INTERFACE ".InvalidOptions" -#define WPAS_ERROR_INVALID_IFACE \ - WPAS_DBUS_INTERFACE ".InvalidInterface" - -#define WPAS_ERROR_ADD_ERROR \ - WPAS_DBUS_INTERFACE ".AddError" -#define WPAS_ERROR_EXISTS_ERROR \ - WPAS_DBUS_INTERFACE ".ExistsError" -#define WPAS_ERROR_REMOVE_ERROR \ - WPAS_DBUS_INTERFACE ".RemoveError" - -#define WPAS_ERROR_SCAN_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".ScanError" -#define WPAS_ERROR_ADD_NETWORK_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError" -#define WPAS_ERROR_INTERNAL_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".InternalError" -#define WPAS_ERROR_REMOVE_NETWORK_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError" - -#define WPAS_ERROR_WPS_PBC_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError" -#define WPAS_ERROR_WPS_PIN_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".WpsPinError" -#define WPAS_ERROR_WPS_REG_ERROR \ - WPAS_DBUS_IFACE_INTERFACE ".WpsRegError" - -#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" - -struct wpa_global; -struct wpa_supplicant; - -int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface); -void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s); -void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s); -void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, - enum wpa_states new_state, - enum wpa_states old_state); -void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, - const struct wps_credential *cred); -void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, - int depth, const char *subject, - const char *cert_hash, - const struct wpabuf *cert); - -char * wpas_dbus_decompose_object_path(const char *path, char **network, - char **bssid); - -int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s); -int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s); - - -/* Methods internal to the dbus control interface */ -struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( - struct wpa_global *global, const char *path); - -#else /* CONFIG_CTRL_IFACE_DBUS */ - -static inline void -wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) -{ -} - -static inline void -wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) -{ -} - -static inline void -wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, - enum wpa_states new_state, - enum wpa_states old_state) -{ -} - -static inline void -wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, - const struct wps_credential *cred) -{ -} - -static inline void -wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, - int depth, const char *subject, - const char *cert_hash, - const struct wpabuf *cert) -{ -} - -static inline int -wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) -{ - return 0; -} - -static inline int -wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) -{ - return 0; -} - -#endif /* CONFIG_CTRL_IFACE_DBUS */ - -#endif /* CTRL_IFACE_DBUS_H */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c deleted file mode 100644 index e540832f254b..000000000000 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c +++ /dev/null @@ -1,1393 +0,0 @@ -/* - * WPA Supplicant / dbus-based control interface - * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include <dbus/dbus.h> - -#include "common.h" -#include "eap_peer/eap_methods.h" -#include "common/ieee802_11_defs.h" -#include "eapol_supp/eapol_supp_sm.h" -#include "rsn_supp/wpa.h" -#include "../config.h" -#include "../wpa_supplicant_i.h" -#include "../driver_i.h" -#include "../notify.h" -#include "../wpas_glue.h" -#include "../bss.h" -#include "../scan.h" -#include "dbus_old.h" -#include "dbus_old_handlers.h" -#include "dbus_dict_helpers.h" - -/** - * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message - * @message: Pointer to incoming dbus message this error refers to - * Returns: a dbus error message - * - * Convenience function to create and return an invalid options error - */ -DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, - const char *arg) -{ - DBusMessage *reply; - - reply = dbus_message_new_error( - message, WPAS_ERROR_INVALID_OPTS, - "Did not receive correct message arguments."); - if (arg != NULL) - dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, - DBUS_TYPE_INVALID); - - return reply; -} - - -/** - * wpas_dbus_new_success_reply - Return a new success reply message - * @message: Pointer to incoming dbus message this reply refers to - * Returns: a dbus message containing a single UINT32 that indicates - * success (ie, a value of 1) - * - * Convenience function to create and return a success reply message - */ -DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) -{ - DBusMessage *reply; - unsigned int success = 1; - - reply = dbus_message_new_method_return(message); - dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, - DBUS_TYPE_INVALID); - return reply; -} - - -/** - * wpas_dbus_global_add_interface - Request registration of a network interface - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: The object path of the new interface object, - * or a dbus error message with more information - * - * Handler function for "addInterface" method call. Handles requests - * by dbus clients to register a network interface that wpa_supplicant - * will manage. - */ -DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, - struct wpa_global *global) -{ - char *ifname = NULL; - char *driver = NULL; - char *driver_param = NULL; - char *confname = NULL; - char *bridge_ifname = NULL; - DBusMessage *reply = NULL; - DBusMessageIter iter; - - dbus_message_iter_init(message, &iter); - - /* First argument: interface name (DBUS_TYPE_STRING) - * Required; must be non-zero length - */ - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - goto error; - dbus_message_iter_get_basic(&iter, &ifname); - if (!os_strlen(ifname)) - goto error; - - /* Second argument: dict of options */ - if (dbus_message_iter_next(&iter)) { - DBusMessageIter iter_dict; - struct wpa_dbus_dict_entry entry; - - if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) - goto error; - while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) - goto error; - if (!strcmp(entry.key, "driver") && - entry.type == DBUS_TYPE_STRING) { - os_free(driver); - driver = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (driver == NULL) - goto error; - } else if (!strcmp(entry.key, "driver-params") && - entry.type == DBUS_TYPE_STRING) { - os_free(driver_param); - driver_param = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (driver_param == NULL) - goto error; - } else if (!strcmp(entry.key, "config-file") && - entry.type == DBUS_TYPE_STRING) { - os_free(confname); - confname = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (confname == NULL) - goto error; - } else if (!strcmp(entry.key, "bridge-ifname") && - entry.type == DBUS_TYPE_STRING) { - os_free(bridge_ifname); - bridge_ifname = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (bridge_ifname == NULL) - goto error; - } else { - wpa_dbus_dict_entry_clear(&entry); - goto error; - } - } - } - - /* - * Try to get the wpa_supplicant record for this iface, return - * an error if we already control it. - */ - if (wpa_supplicant_get_iface(global, ifname) != NULL) { - reply = dbus_message_new_error( - message, WPAS_ERROR_EXISTS_ERROR, - "wpa_supplicant already controls this interface."); - } else { - struct wpa_supplicant *wpa_s; - struct wpa_interface iface; - - os_memset(&iface, 0, sizeof(iface)); - iface.ifname = ifname; - iface.driver = driver; - iface.driver_param = driver_param; - iface.confname = confname; - iface.bridge_ifname = bridge_ifname; - /* Otherwise, have wpa_supplicant attach to it. */ - wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); - if (wpa_s && wpa_s->dbus_path) { - const char *path = wpa_s->dbus_path; - - reply = dbus_message_new_method_return(message); - dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, - &path, DBUS_TYPE_INVALID); - } else { - reply = dbus_message_new_error( - message, WPAS_ERROR_ADD_ERROR, - "wpa_supplicant couldn't grab this interface."); - } - } - -out: - os_free(driver); - os_free(driver_param); - os_free(confname); - os_free(bridge_ifname); - return reply; - -error: - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; -} - - -/** - * wpas_dbus_global_remove_interface - Request deregistration of an interface - * @message: Pointer to incoming dbus message - * @global: wpa_supplicant global data structure - * Returns: a dbus message containing a UINT32 indicating success (1) or - * failure (0), or returns a dbus error message with more information - * - * Handler function for "removeInterface" method call. Handles requests - * by dbus clients to deregister a network interface that wpa_supplicant - * currently manages. - */ -DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, - struct wpa_global *global) -{ - struct wpa_supplicant *wpa_s; - char *path; - DBusMessage *reply = NULL; - - if (!dbus_message_get_args(message, NULL, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; - } - - wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); - if (wpa_s == NULL) { - reply = wpas_dbus_new_invalid_iface_error(message); - goto out; - } - - if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) { - reply = wpas_dbus_new_success_reply(message); - } else { - reply = dbus_message_new_error( - message, WPAS_ERROR_REMOVE_ERROR, - "wpa_supplicant couldn't remove this interface."); - } - -out: - return reply; -} - - -/** - * wpas_dbus_global_get_interface - Get the object path for an interface name - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: The object path of the interface object, - * or a dbus error message with more information - * - * Handler function for "getInterface" method call. Handles requests - * by dbus clients for the object path of an specific network interface. - */ -DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, - struct wpa_global *global) -{ - DBusMessage *reply = NULL; - const char *ifname; - const char *path; - struct wpa_supplicant *wpa_s; - - if (!dbus_message_get_args(message, NULL, - DBUS_TYPE_STRING, &ifname, - DBUS_TYPE_INVALID)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; - } - - wpa_s = wpa_supplicant_get_iface(global, ifname); - if (wpa_s == NULL || !wpa_s->dbus_path) { - reply = wpas_dbus_new_invalid_iface_error(message); - goto out; - } - - path = wpa_s->dbus_path; - reply = dbus_message_new_method_return(message); - dbus_message_append_args(reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - -out: - return reply; -} - - -/** - * wpas_dbus_global_set_debugparams- Set the debug params - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: a dbus message containing a UINT32 indicating success (1) or - * failure (0), or returns a dbus error message with more information - * - * Handler function for "setDebugParams" method call. Handles requests - * by dbus clients for the object path of an specific network interface. - */ -DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, - struct wpa_global *global) -{ - DBusMessage *reply = NULL; - int debug_level; - dbus_bool_t debug_timestamp; - dbus_bool_t debug_show_keys; - - if (!dbus_message_get_args(message, NULL, - DBUS_TYPE_INT32, &debug_level, - DBUS_TYPE_BOOLEAN, &debug_timestamp, - DBUS_TYPE_BOOLEAN, &debug_show_keys, - DBUS_TYPE_INVALID)) { - return wpas_dbus_new_invalid_opts_error(message, NULL); - } - - if (wpa_supplicant_set_debug_params(global, debug_level, - debug_timestamp ? 1 : 0, - debug_show_keys ? 1 : 0)) { - return wpas_dbus_new_invalid_opts_error(message, NULL); - } - - reply = wpas_dbus_new_success_reply(message); - - return reply; -} - - -/** - * wpas_dbus_iface_scan - Request a wireless scan on an interface - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: a dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "scan" method call of a network device. Requests - * that wpa_supplicant perform a wireless scan as soon as possible - * on a particular wireless interface. - */ -DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_supplicant_req_scan(wpa_s, 0, 0); - return wpas_dbus_new_success_reply(message); -} - - -/** - * wpas_dbus_iface_scan_results - Get the results of a recent scan request - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: a dbus message containing a dbus array of objects paths, or returns - * a dbus error message if not scan results could be found - * - * Handler function for "scanResults" method call of a network device. Returns - * a dbus message containing the object paths of wireless networks found. - */ -DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter sub_iter; - struct wpa_bss *bss; - - if (!wpa_s->dbus_path) - return dbus_message_new_error(message, - WPAS_ERROR_INTERNAL_ERROR, - "no D-Bus interface available"); - - /* Create and initialize the return message */ - reply = dbus_message_new_method_return(message); - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH_AS_STRING, - &sub_iter)) - goto error; - - /* Loop through scan results and append each result's object path */ - dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { - char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; - char *path = path_buf; - - /* Construct the object path for this network. Note that ':' - * is not a valid character in dbus object paths. - */ - os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, - "%s/" WPAS_DBUS_BSSIDS_PART "/" - WPAS_DBUS_BSSID_FORMAT, - wpa_s->dbus_path, MAC2STR(bss->bssid)); - if (!dbus_message_iter_append_basic(&sub_iter, - DBUS_TYPE_OBJECT_PATH, - &path)) - goto error; - } - - if (!dbus_message_iter_close_container(&iter, &sub_iter)) - goto error; - - return reply; - -error: - dbus_message_unref(reply); - return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, - "an internal error occurred returning scan results"); -} - - -/** - * wpas_dbus_bssid_properties - Return the properties of a scanned network - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * @res: wpa_supplicant scan result for which to get properties - * Returns: a dbus message containing the properties for the requested network - * - * Handler function for "properties" method call of a scanned network. - * Returns a dbus message containing the the properties. - */ -DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_bss *bss) -{ - DBusMessage *reply; - DBusMessageIter iter, iter_dict; - const u8 *wpa_ie, *rsn_ie, *wps_ie; - - /* Dump the properties into a dbus message */ - reply = dbus_message_new_method_return(message); - - wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); - rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); - wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); - - dbus_message_iter_init_append(reply, &iter); - if (!wpa_dbus_dict_open_write(&iter, &iter_dict) || - !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", - (const char *) bss->bssid, - ETH_ALEN) || - !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", - (const char *) bss->ssid, - bss->ssid_len) || - (wpa_ie && - !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", - (const char *) wpa_ie, - wpa_ie[1] + 2)) || - (rsn_ie && - !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", - (const char *) rsn_ie, - rsn_ie[1] + 2)) || - (wps_ie && - !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie", - (const char *) wps_ie, - wps_ie[1] + 2)) || - (bss->freq && - !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) || - !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", - bss->caps) || - (!(bss->flags & WPA_BSS_QUAL_INVALID) && - !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) || - (!(bss->flags & WPA_BSS_NOISE_INVALID) && - !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) || - (!(bss->flags & WPA_BSS_LEVEL_INVALID) && - !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) || - !wpa_dbus_dict_append_int32(&iter_dict, "maxrate", - wpa_bss_get_max_rate(bss) * 500000) || - !wpa_dbus_dict_close_write(&iter, &iter_dict)) { - if (reply) - dbus_message_unref(reply); - reply = dbus_message_new_error( - message, WPAS_ERROR_INTERNAL_ERROR, - "an internal error occurred returning BSSID properties."); - } - - return reply; -} - - -/** - * wpas_dbus_iface_capabilities - Return interface capabilities - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a dict of strings - * - * Handler function for "capabilities" method call of an interface. - */ -DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - struct wpa_driver_capa capa; - int res; - DBusMessageIter iter, iter_dict; - char **eap_methods; - size_t num_items; - dbus_bool_t strict = FALSE; - DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; - - if (!dbus_message_get_args(message, NULL, - DBUS_TYPE_BOOLEAN, &strict, - DBUS_TYPE_INVALID)) - strict = FALSE; - - reply = dbus_message_new_method_return(message); - - dbus_message_iter_init_append(reply, &iter); - if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) - goto error; - - /* EAP methods */ - eap_methods = eap_get_names_as_string_array(&num_items); - if (eap_methods) { - dbus_bool_t success; - size_t i = 0; - - success = wpa_dbus_dict_append_string_array( - &iter_dict, "eap", (const char **) eap_methods, - num_items); - - /* free returned method array */ - while (eap_methods[i]) - os_free(eap_methods[i++]); - os_free(eap_methods); - - if (!success) - goto error; - } - - res = wpa_drv_get_capa(wpa_s, &capa); - - /***** pairwise cipher */ - if (res < 0) { - if (!strict) { - const char *args[] = {"CCMP", "TKIP", "NONE"}; - - if (!wpa_dbus_dict_append_string_array( - &iter_dict, "pairwise", args, - ARRAY_SIZE(args))) - goto error; - } - } else { - if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", - &iter_dict_entry, - &iter_dict_val, - &iter_array) || - ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "CCMP")) || - ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "TKIP")) || - ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "NONE")) || - !wpa_dbus_dict_end_string_array(&iter_dict, - &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto error; - } - - /***** group cipher */ - if (res < 0) { - if (!strict) { - const char *args[] = { - "CCMP", "TKIP", "WEP104", "WEP40" - }; - - if (!wpa_dbus_dict_append_string_array( - &iter_dict, "group", args, - ARRAY_SIZE(args))) - goto error; - } - } else { - if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", - &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto error; - - if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "CCMP")) || - ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "TKIP")) || - ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "WEP104")) || - ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "WEP40")) || - !wpa_dbus_dict_end_string_array(&iter_dict, - &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto error; - } - - /***** key management */ - if (res < 0) { - if (!strict) { - const char *args[] = { - "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", - "NONE" - }; - if (!wpa_dbus_dict_append_string_array( - &iter_dict, "key_mgmt", args, - ARRAY_SIZE(args))) - goto error; - } - } else { - if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", - &iter_dict_entry, - &iter_dict_val, - &iter_array) || - !wpa_dbus_dict_string_array_add_element(&iter_array, - "NONE") || - !wpa_dbus_dict_string_array_add_element(&iter_array, - "IEEE8021X") || - ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "WPA-EAP")) || - ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "WPA-PSK")) || - ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "WPA-NONE")) || - !wpa_dbus_dict_end_string_array(&iter_dict, - &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto error; - } - - /***** WPA protocol */ - if (res < 0) { - if (!strict) { - const char *args[] = { "RSN", "WPA" }; - - if (!wpa_dbus_dict_append_string_array( - &iter_dict, "proto", args, - ARRAY_SIZE(args))) - goto error; - } - } else { - if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", - &iter_dict_entry, - &iter_dict_val, - &iter_array) || - ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "RSN")) || - ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "WPA")) || - !wpa_dbus_dict_end_string_array(&iter_dict, - &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto error; - } - - /***** auth alg */ - if (res < 0) { - if (!strict) { - const char *args[] = { "OPEN", "SHARED", "LEAP" }; - - if (!wpa_dbus_dict_append_string_array( - &iter_dict, "auth_alg", args, - ARRAY_SIZE(args))) - goto error; - } - } else { - if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", - &iter_dict_entry, - &iter_dict_val, - &iter_array) || - ((capa.auth & WPA_DRIVER_AUTH_OPEN) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "OPEN")) || - ((capa.auth & WPA_DRIVER_AUTH_SHARED) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "SHARED")) || - ((capa.auth & WPA_DRIVER_AUTH_LEAP) && - !wpa_dbus_dict_string_array_add_element( - &iter_array, "LEAP")) || - !wpa_dbus_dict_end_string_array(&iter_dict, - &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto error; - } - - if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) - goto error; - - return reply; - -error: - if (reply) - dbus_message_unref(reply); - return dbus_message_new_error( - message, WPAS_ERROR_INTERNAL_ERROR, - "an internal error occurred returning interface capabilities."); -} - - -/** - * wpas_dbus_iface_add_network - Add a new configured network - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing the object path of the new network - * - * Handler function for "addNetwork" method call of a network interface. - */ -DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - struct wpa_ssid *ssid = NULL; - char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; - - if (wpa_s->dbus_path) - ssid = wpa_supplicant_add_network(wpa_s); - if (ssid == NULL) { - reply = dbus_message_new_error( - message, WPAS_ERROR_ADD_NETWORK_ERROR, - "wpa_supplicant could not add a network on this interface."); - goto out; - } - - /* Construct the object path for this network. */ - os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, - "%s/" WPAS_DBUS_NETWORKS_PART "/%d", - wpa_s->dbus_path, ssid->id); - - reply = dbus_message_new_method_return(message); - dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, - &path, DBUS_TYPE_INVALID); - -out: - return reply; -} - - -/** - * wpas_dbus_iface_remove_network - Remove a configured network - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "removeNetwork" method call of a network interface. - */ -DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - const char *op; - char *iface = NULL, *net_id = NULL; - int id; - int result; - - if (!dbus_message_get_args(message, NULL, - DBUS_TYPE_OBJECT_PATH, &op, - DBUS_TYPE_INVALID)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; - } - - /* Extract the network ID */ - iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); - if (iface == NULL || net_id == NULL) { - reply = wpas_dbus_new_invalid_network_error(message); - goto out; - } - - /* Ensure the network is actually a child of this interface */ - if (!wpa_s->dbus_path || os_strcmp(iface, wpa_s->dbus_path) != 0) { - reply = wpas_dbus_new_invalid_network_error(message); - goto out; - } - - id = strtoul(net_id, NULL, 10); - result = wpa_supplicant_remove_network(wpa_s, id); - if (result == -1) { - reply = wpas_dbus_new_invalid_network_error(message); - goto out; - } - if (result == -2) { - reply = dbus_message_new_error( - message, WPAS_ERROR_REMOVE_NETWORK_ERROR, - "error removing the specified on this interface."); - goto out; - } - - reply = wpas_dbus_new_success_reply(message); - -out: - os_free(iface); - os_free(net_id); - return reply; -} - - -static const char * const dont_quote[] = { - "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", - "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", - "bssid", "scan_freq", "freq_list", NULL -}; - - -static dbus_bool_t should_quote_opt(const char *key) -{ - int i = 0; - - while (dont_quote[i] != NULL) { - if (os_strcmp(key, dont_quote[i]) == 0) - return FALSE; - i++; - } - return TRUE; -} - - -/** - * wpas_dbus_iface_set_network - Set options for a configured network - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * @ssid: wpa_ssid structure for a configured network - * Returns: a dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "set" method call of a configured network. - */ -DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid) -{ - DBusMessage *reply = NULL; - struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; - DBusMessageIter iter, iter_dict; - - dbus_message_iter_init(message, &iter); - - if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; - } - - while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - char *value = NULL; - size_t size = 50; - int ret; - - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { - reply = wpas_dbus_new_invalid_opts_error(message, - NULL); - goto out; - } - - /* Type conversions, since wpa_supplicant wants strings */ - if (entry.type == DBUS_TYPE_ARRAY && - entry.array_type == DBUS_TYPE_BYTE) { - if (entry.array_len <= 0) - goto error; - - size = entry.array_len * 2 + 1; - value = os_zalloc(size); - if (value == NULL) - goto error; - ret = wpa_snprintf_hex(value, size, - (u8 *) entry.bytearray_value, - entry.array_len); - if (ret <= 0) - goto error; - } else if (entry.type == DBUS_TYPE_STRING) { - if (should_quote_opt(entry.key)) { - size = os_strlen(entry.str_value); - /* Zero-length option check */ - if (size == 0) - goto error; - size += 3; /* For quotes and terminator */ - value = os_zalloc(size); - if (value == NULL) - goto error; - ret = os_snprintf(value, size, "\"%s\"", - entry.str_value); - if (os_snprintf_error(size, ret)) - goto error; - } else { - value = os_strdup(entry.str_value); - if (value == NULL) - goto error; - } - } else if (entry.type == DBUS_TYPE_UINT32) { - value = os_zalloc(size); - if (value == NULL) - goto error; - ret = os_snprintf(value, size, "%u", - entry.uint32_value); - if (os_snprintf_error(size, ret)) - goto error; - } else if (entry.type == DBUS_TYPE_INT32) { - value = os_zalloc(size); - if (value == NULL) - goto error; - ret = os_snprintf(value, size, "%d", - entry.int32_value); - if (os_snprintf_error(size, ret)) - goto error; - } else - goto error; - - if (wpa_config_set(ssid, entry.key, value, 0) < 0) - goto error; - - if ((os_strcmp(entry.key, "psk") == 0 && - value[0] == '"' && ssid->ssid_len) || - (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) - wpa_config_update_psk(ssid); - else if (os_strcmp(entry.key, "priority") == 0) - wpa_config_update_prio_list(wpa_s->conf); - - os_free(value); - wpa_dbus_dict_entry_clear(&entry); - continue; - - error: - os_free(value); - reply = wpas_dbus_new_invalid_opts_error(message, entry.key); - wpa_dbus_dict_entry_clear(&entry); - break; - } - - if (!reply) - reply = wpas_dbus_new_success_reply(message); - -out: - return reply; -} - - -/** - * wpas_dbus_iface_enable_network - Mark a configured network as enabled - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * @ssid: wpa_ssid structure for a configured network - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "enable" method call of a configured network. - */ -DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid) -{ - wpa_supplicant_enable_network(wpa_s, ssid); - return wpas_dbus_new_success_reply(message); -} - - -/** - * wpas_dbus_iface_disable_network - Mark a configured network as disabled - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * @ssid: wpa_ssid structure for a configured network - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "disable" method call of a configured network. - */ -DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid) -{ - wpa_supplicant_disable_network(wpa_s, ssid); - return wpas_dbus_new_success_reply(message); -} - - -/** - * wpas_dbus_iface_select_network - Attempt association with a configured network - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "selectNetwork" method call of network interface. - */ -DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - const char *op; - struct wpa_ssid *ssid; - char *iface_obj_path = NULL; - char *network = NULL; - - if (os_strlen(dbus_message_get_signature(message)) == 0) { - /* Any network */ - ssid = NULL; - } else { - int nid; - - if (!dbus_message_get_args(message, NULL, - DBUS_TYPE_OBJECT_PATH, &op, - DBUS_TYPE_INVALID)) { - reply = wpas_dbus_new_invalid_opts_error(message, - NULL); - goto out; - } - - /* Extract the network number */ - iface_obj_path = wpas_dbus_decompose_object_path(op, - &network, - NULL); - if (iface_obj_path == NULL) { - reply = wpas_dbus_new_invalid_iface_error(message); - goto out; - } - /* Ensure the object path really points to this interface */ - if (network == NULL || !wpa_s->dbus_path || - os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) { - reply = wpas_dbus_new_invalid_network_error(message); - goto out; - } - - nid = strtoul(network, NULL, 10); - if (errno == EINVAL) { - reply = wpas_dbus_new_invalid_network_error(message); - goto out; - } - - ssid = wpa_config_get_network(wpa_s->conf, nid); - if (ssid == NULL) { - reply = wpas_dbus_new_invalid_network_error(message); - goto out; - } - } - - /* Finally, associate with the network */ - wpa_supplicant_select_network(wpa_s, ssid); - - reply = wpas_dbus_new_success_reply(message); - -out: - os_free(iface_obj_path); - os_free(network); - return reply; -} - - -/** - * wpas_dbus_iface_disconnect - Terminate the current connection - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "disconnect" method call of network interface. - */ -DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - wpas_request_disconnection(wpa_s); - - return wpas_dbus_new_success_reply(message); -} - - -/** - * wpas_dbus_iface_set_ap_scan - Control roaming mode - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "setAPScan" method call. - */ -DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - dbus_uint32_t ap_scan = 1; - - if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, - DBUS_TYPE_INVALID)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; - } - - if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; - } - - reply = wpas_dbus_new_success_reply(message); - -out: - return reply; -} - - -/** - * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "setSmartcardModules" method call. - */ -DBusMessage * wpas_dbus_iface_set_smartcard_modules( - DBusMessage *message, struct wpa_supplicant *wpa_s) -{ - DBusMessageIter iter, iter_dict; - char *opensc_engine_path = NULL; - char *pkcs11_engine_path = NULL; - char *pkcs11_module_path = NULL; - struct wpa_dbus_dict_entry entry; - - if (!dbus_message_iter_init(message, &iter)) - goto error; - - if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) - goto error; - - while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) - goto error; - if (!strcmp(entry.key, "opensc_engine_path") && - entry.type == DBUS_TYPE_STRING) { - os_free(opensc_engine_path); - opensc_engine_path = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (opensc_engine_path == NULL) - goto error; - } else if (!strcmp(entry.key, "pkcs11_engine_path") && - entry.type == DBUS_TYPE_STRING) { - os_free(pkcs11_engine_path); - pkcs11_engine_path = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (pkcs11_engine_path == NULL) - goto error; - } else if (!strcmp(entry.key, "pkcs11_module_path") && - entry.type == DBUS_TYPE_STRING) { - os_free(pkcs11_module_path); - pkcs11_module_path = os_strdup(entry.str_value); - wpa_dbus_dict_entry_clear(&entry); - if (pkcs11_module_path == NULL) - goto error; - } else { - wpa_dbus_dict_entry_clear(&entry); - goto error; - } - } - - os_free(wpa_s->conf->opensc_engine_path); - wpa_s->conf->opensc_engine_path = opensc_engine_path; - os_free(wpa_s->conf->pkcs11_engine_path); - wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path; - os_free(wpa_s->conf->pkcs11_module_path); - wpa_s->conf->pkcs11_module_path = pkcs11_module_path; - - wpa_sm_set_eapol(wpa_s->wpa, NULL); - eapol_sm_deinit(wpa_s->eapol); - wpa_s->eapol = NULL; - wpa_supplicant_init_eapol(wpa_s); - wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); - - return wpas_dbus_new_success_reply(message); - -error: - os_free(opensc_engine_path); - os_free(pkcs11_engine_path); - os_free(pkcs11_module_path); - return wpas_dbus_new_invalid_opts_error(message, NULL); -} - - -/** - * wpas_dbus_iface_get_state - Get interface state - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a STRING representing the current - * interface state - * - * Handler function for "state" method call. - */ -DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - const char *str_state; - - reply = dbus_message_new_method_return(message); - if (reply != NULL) { - str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, - DBUS_TYPE_INVALID); - } - - return reply; -} - - -/** - * wpas_dbus_iface_get_scanning - Get interface scanning state - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing whether the interface is scanning - * - * Handler function for "scanning" method call. - */ -DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; - - reply = dbus_message_new_method_return(message); - if (reply != NULL) { - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning, - DBUS_TYPE_INVALID); - } else { - wpa_printf(MSG_ERROR, - "dbus: Not enough memory to return scanning state"); - } - - return reply; -} - - -#ifndef CONFIG_NO_CONFIG_BLOBS - -/** - * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates) - * @message: Pointer to incoming dbus message - * @wpa_s: %wpa_supplicant data structure - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Asks wpa_supplicant to internally store a one or more binary blobs. - */ -DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; - DBusMessageIter iter, iter_dict; - - dbus_message_iter_init(message, &iter); - - if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) - return wpas_dbus_new_invalid_opts_error(message, NULL); - - while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - struct wpa_config_blob *blob; - - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { - reply = wpas_dbus_new_invalid_opts_error(message, - NULL); - break; - } - - if (entry.type != DBUS_TYPE_ARRAY || - entry.array_type != DBUS_TYPE_BYTE) { - reply = wpas_dbus_new_invalid_opts_error( - message, "Byte array expected."); - break; - } - - if ((entry.array_len <= 0) || (entry.array_len > 65536) || - !strlen(entry.key)) { - reply = wpas_dbus_new_invalid_opts_error( - message, "Invalid array size."); - break; - } - - blob = os_zalloc(sizeof(*blob)); - if (blob == NULL) { - reply = dbus_message_new_error( - message, WPAS_ERROR_ADD_ERROR, - "Not enough memory to add blob."); - break; - } - blob->data = os_zalloc(entry.array_len); - if (blob->data == NULL) { - reply = dbus_message_new_error( - message, WPAS_ERROR_ADD_ERROR, - "Not enough memory to add blob data."); - os_free(blob); - break; - } - - blob->name = os_strdup(entry.key); - blob->len = entry.array_len; - os_memcpy(blob->data, (u8 *) entry.bytearray_value, - entry.array_len); - if (blob->name == NULL) { - wpa_config_free_blob(blob); - reply = dbus_message_new_error( - message, WPAS_ERROR_ADD_ERROR, - "Error adding blob."); - break; - } - - /* Success */ - if (!wpa_config_remove_blob(wpa_s->conf, blob->name)) - wpas_notify_blob_removed(wpa_s, blob->name); - wpa_config_set_blob(wpa_s->conf, blob); - wpas_notify_blob_added(wpa_s, blob->name); - - wpa_dbus_dict_entry_clear(&entry); - } - wpa_dbus_dict_entry_clear(&entry); - - return reply ? reply : wpas_dbus_new_success_reply(message); -} - - -/** - * wpas_dbus_iface_remove_blob - Remove named binary blobs - * @message: Pointer to incoming dbus message - * @wpa_s: %wpa_supplicant data structure - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Asks wpa_supplicant to remove one or more previously stored binary blobs. - */ -DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessageIter iter, array; - char *err_msg = NULL; - - dbus_message_iter_init(message, &iter); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) - return wpas_dbus_new_invalid_opts_error(message, NULL); - - dbus_message_iter_recurse(&iter, &array); - while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { - const char *name; - - dbus_message_iter_get_basic(&array, &name); - if (!os_strlen(name)) - err_msg = "Invalid blob name."; - else if (wpa_config_remove_blob(wpa_s->conf, name) != 0) - err_msg = "Error removing blob."; - else - wpas_notify_blob_removed(wpa_s, name); - dbus_message_iter_next(&array); - } - - if (err_msg) - return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, - err_msg); - - return wpas_dbus_new_success_reply(message); -} - -#endif /* CONFIG_NO_CONFIG_BLOBS */ - - -/** - * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries - * @message: Pointer to incoming dbus message - * @wpa_s: %wpa_supplicant data structure - * Returns: a dbus message containing a UINT32 indicating success (1) or - * failure (0), or returns a dbus error message with more information - * - * Handler function for "flush" method call. Handles requests for an - * interface with an optional "age" parameter that specifies the minimum - * age of a BSS to be flushed. - */ -DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - int flush_age = 0; - - if (os_strlen(dbus_message_get_signature(message)) != 0 && - !dbus_message_get_args(message, NULL, - DBUS_TYPE_INT32, &flush_age, - DBUS_TYPE_INVALID)) { - return wpas_dbus_new_invalid_opts_error(message, NULL); - } - - if (flush_age == 0) - wpa_bss_flush(wpa_s); - else - wpa_bss_flush_by_age(wpa_s, flush_age); - - return wpas_dbus_new_success_reply(message); -} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h deleted file mode 100644 index e60ad06a032e..000000000000 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * WPA Supplicant / dbus-based control interface - * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef CTRL_IFACE_DBUS_HANDLERS_H -#define CTRL_IFACE_DBUS_HANDLERS_H - -struct wpa_bss; - -DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); -DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message); - -DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, - struct wpa_global *global); - -DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, - struct wpa_global *global); - -DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, - struct wpa_global *global); - -DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, - struct wpa_global *global); - -DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_bss *bss); - -DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid); - -DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid); - -DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid); - -DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_set_smartcard_modules( - DBusMessage *message, struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, - struct wpa_supplicant *wpa_s); - -DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message); -DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, - const char *arg); - -#endif /* CTRL_IFACE_DBUS_HANDLERS_H */ - diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c deleted file mode 100644 index 5309a5301fc2..000000000000 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * WPA Supplicant / dbus-based control interface (WPS) - * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include <dbus/dbus.h> - -#include "common.h" -#include "../config.h" -#include "../wpa_supplicant_i.h" -#include "../wps_supplicant.h" -#include "dbus_old.h" -#include "dbus_old_handlers.h" - -/** - * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method - * @message: Pointer to incoming dbus message - * @wpa_s: %wpa_supplicant data structure - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "wpsPbc" method call - */ -DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - char *arg_bssid = NULL; - u8 bssid[ETH_ALEN]; - int ret = 0; - - if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, - DBUS_TYPE_INVALID)) - return wpas_dbus_new_invalid_opts_error(message, NULL); - - if (os_strcmp(arg_bssid, "any") == 0) - ret = wpas_wps_start_pbc(wpa_s, NULL, 0); - else if (!hwaddr_aton(arg_bssid, bssid)) - ret = wpas_wps_start_pbc(wpa_s, bssid, 0); - else { - return wpas_dbus_new_invalid_opts_error(message, - "Invalid BSSID"); - } - - if (ret < 0) { - return dbus_message_new_error( - message, WPAS_ERROR_WPS_PBC_ERROR, - "Could not start PBC negotiation"); - } - - return wpas_dbus_new_success_reply(message); -} - - -/** - * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee - * @message: Pointer to incoming dbus message - * @wpa_s: %wpa_supplicant data structure - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "wpsPin" method call - */ -DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - DBusMessage *reply = NULL; - char *arg_bssid; - char *pin = NULL; - u8 bssid[ETH_ALEN], *_bssid = NULL; - int ret = 0; - char npin[9]; - - if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, - DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) - return wpas_dbus_new_invalid_opts_error(message, NULL); - - if (os_strcmp(arg_bssid, "any") == 0) - _bssid = NULL; - else if (!hwaddr_aton(arg_bssid, bssid)) - _bssid = bssid; - else { - return wpas_dbus_new_invalid_opts_error(message, - "Invalid BSSID"); - } - - if (os_strlen(pin) > 0) - ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, - DEV_PW_DEFAULT); - else - ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, - DEV_PW_DEFAULT); - - if (ret < 0) { - return dbus_message_new_error(message, - WPAS_ERROR_WPS_PIN_ERROR, - "Could not init PIN"); - } - - reply = dbus_message_new_method_return(message); - if (reply == NULL) - return NULL; - - if (ret > 0) { - os_snprintf(npin, sizeof(npin), "%08d", ret); - pin = npin; - } - dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin, - DBUS_TYPE_INVALID); - return reply; -} - - -/** - * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP - * @message: Pointer to incoming dbus message - * @wpa_s: %wpa_supplicant data structure - * Returns: A dbus message containing a UINT32 indicating success (1) or - * failure (0) - * - * Handler function for "wpsReg" method call - */ -DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, - struct wpa_supplicant *wpa_s) -{ - char *arg_bssid; - char *pin = NULL; - u8 bssid[ETH_ALEN]; - int ret = 0; - - if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, - DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) - return wpas_dbus_new_invalid_opts_error(message, NULL); - - if (!hwaddr_aton(arg_bssid, bssid)) - ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL); - else { - return wpas_dbus_new_invalid_opts_error(message, - "Invalid BSSID"); - } - - if (ret < 0) { - return dbus_message_new_error(message, - WPAS_ERROR_WPS_REG_ERROR, - "Could not request credentials"); - } - - return wpas_dbus_new_success_reply(message); -} diff --git a/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in b/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in deleted file mode 100644 index a75918f9380b..000000000000 --- a/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in +++ /dev/null @@ -1,5 +0,0 @@ -[D-BUS Service] -Name=fi.epitest.hostap.WPASupplicant -Exec=@BINDIR@/wpa_supplicant -u -User=root -SystemdService=wpa_supplicant.service diff --git a/contrib/wpa/wpa_supplicant/defconfig b/contrib/wpa/wpa_supplicant/defconfig index 1d05198f849a..88cd79085f6d 100644 --- a/contrib/wpa/wpa_supplicant/defconfig +++ b/contrib/wpa/wpa_supplicant/defconfig @@ -1,9 +1,9 @@ # Example wpa_supplicant build time configuration # # This file lists the configuration options that are used when building the -# hostapd binary. All lines starting with # are ignored. Configuration option -# lines must be commented out complete, if they are not to be included, i.e., -# just setting VARIABLE=n is not disabling that variable. +# wpa_supplicant binary. All lines starting with # are ignored. Configuration +# option lines must be commented out complete, if they are not to be included, +# i.e., just setting VARIABLE=n is not disabling that variable. # # This file is included in Makefile, so variables like CFLAGS and LIBS can also # be modified from here. In most cases, these lines should use += in order not @@ -44,7 +44,7 @@ CONFIG_DRIVER_NL80211=y #CONFIG_LIBNL20=y # Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) -#CONFIG_LIBNL32=y +CONFIG_LIBNL32=y # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) @@ -73,6 +73,12 @@ CONFIG_DRIVER_NL80211=y # Driver interface for wired Ethernet drivers CONFIG_DRIVER_WIRED=y +# Driver interface for MACsec capable Qualcomm Atheros drivers +#CONFIG_DRIVER_MACSEC_QCA=y + +# Driver interface for Linux MACsec drivers +#CONFIG_DRIVER_MACSEC_LINUX=y + # Driver interface for the Broadcom RoboSwitch family #CONFIG_DRIVER_ROBOSWITCH=y @@ -83,8 +89,8 @@ CONFIG_DRIVER_WIRED=y #LIBS += -lsocket -ldlpi -lnsl #LIBS_c += -lsocket -# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is -# included) +# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or +# MACsec is included) CONFIG_IEEE8021X_EAPOL=y # EAP-MD5 @@ -103,10 +109,7 @@ CONFIG_EAP_PEAP=y CONFIG_EAP_TTLS=y # EAP-FAST -# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed -# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., -# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. -#CONFIG_EAP_FAST=y +CONFIG_EAP_FAST=y # EAP-GTC CONFIG_EAP_GTC=y @@ -121,10 +124,10 @@ CONFIG_EAP_OTP=y #CONFIG_EAP_PSK=y # EAP-pwd (secure authentication using only a password) -#CONFIG_EAP_PWD=y +CONFIG_EAP_PWD=y # EAP-PAX -#CONFIG_EAP_PAX=y +CONFIG_EAP_PAX=y # LEAP CONFIG_EAP_LEAP=y @@ -140,18 +143,18 @@ CONFIG_EAP_LEAP=y #CONFIG_USIM_SIMULATOR=y # EAP-SAKE -#CONFIG_EAP_SAKE=y +CONFIG_EAP_SAKE=y # EAP-GPSK -#CONFIG_EAP_GPSK=y +CONFIG_EAP_GPSK=y # Include support for optional SHA256 cipher suite in EAP-GPSK -#CONFIG_EAP_GPSK_SHA256=y +CONFIG_EAP_GPSK_SHA256=y # EAP-TNC and related Trusted Network Connect support (experimental) -#CONFIG_EAP_TNC=y +CONFIG_EAP_TNC=y # Wi-Fi Protected Setup (WPS) -#CONFIG_WPS=y +CONFIG_WPS=y # Enable WPS external registrar functionality #CONFIG_WPS_ER=y # Disable credentials for an open network by default when acting as a WPS @@ -161,11 +164,14 @@ CONFIG_EAP_LEAP=y #CONFIG_WPS_NFC=y # EAP-IKEv2 -#CONFIG_EAP_IKEV2=y +CONFIG_EAP_IKEV2=y # EAP-EKE #CONFIG_EAP_EKE=y +# MACsec +#CONFIG_MACSEC=y + # PKCS#12 (PFX) support (used to read private key and certificate file from # a file that usually has extension .p12 or .pfx) CONFIG_PKCS12=y @@ -226,6 +232,9 @@ CONFIG_CTRL_IFACE=y # wpa_passphrase). This saves about 0.5 kB in code size. #CONFIG_NO_WPA_PASSPHRASE=y +# Simultaneous Authentication of Equals (SAE), WPA3-Personal +CONFIG_SAE=y + # Disable scan result processing (ap_mode=1) to save code size by about 1 kB. # This can be used if ap_scan=1 mode is never enabled. #CONFIG_NO_SCAN_PROCESSING=y @@ -288,17 +297,18 @@ CONFIG_BACKEND=file # bridge interfaces (commit 'bridge: respect RFC2863 operational state')'). #CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y -# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) -CONFIG_PEERKEY=y - # IEEE 802.11w (management frame protection), also known as PMF # Driver support is also needed for IEEE 802.11w. -#CONFIG_IEEE80211W=y +CONFIG_IEEE80211W=y + +# Support Operating Channel Validation +#CONFIG_OCV=y # Select TLS implementation # openssl = OpenSSL (default) # gnutls = GnuTLS # internal = Internal TLSv1 implementation (experimental) +# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) # none = Empty template #CONFIG_TLS=openssl @@ -316,6 +326,10 @@ CONFIG_PEERKEY=y # will be used) #CONFIG_TLSV12=y +# Select which ciphers to use by default with OpenSSL if the user does not +# specify them. +#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW" + # If CONFIG_TLS=internal is used, additional library and include paths are # needed for LibTomMath. Alternatively, an integrated, minimal version of # LibTomMath can be used. See beginning of libtommath.c for details on benefits @@ -338,16 +352,12 @@ CONFIG_PEERKEY=y #CONFIG_NDIS_EVENTS_INTEGRATED=y #PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" -# Add support for old DBus control interface -# (fi.epitest.hostap.WPASupplicant) -#CONFIG_CTRL_IFACE_DBUS=y - # Add support for new DBus control interface # (fi.w1.hostap.wpa_supplicant1) -#CONFIG_CTRL_IFACE_DBUS_NEW=y +CONFIG_CTRL_IFACE_DBUS_NEW=y # Add introspection support for new DBus control interface -#CONFIG_CTRL_IFACE_DBUS_INTRO=y +CONFIG_CTRL_IFACE_DBUS_INTRO=y # Add support for loading EAP methods dynamically as shared libraries. # When this option is enabled, each EAP method can be either included @@ -370,14 +380,14 @@ CONFIG_PEERKEY=y # amount of memory/flash. #CONFIG_DYNAMIC_EAP_METHODS=y -# IEEE Std 802.11r-2008 (Fast BSS Transition) -#CONFIG_IEEE80211R=y +# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode +CONFIG_IEEE80211R=y # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) -#CONFIG_DEBUG_FILE=y +CONFIG_DEBUG_FILE=y # Send debug messages to syslog instead of stdout -#CONFIG_DEBUG_SYSLOG=y +CONFIG_DEBUG_SYSLOG=y # Set syslog facility for debug messages #CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON @@ -447,12 +457,17 @@ CONFIG_PEERKEY=y # that meet the requirements described above. #CONFIG_NO_RANDOM_POOL=y +# Should we attempt to use the getrandom(2) call that provides more reliable +# yet secure randomness source than /dev/random on Linux 3.17 and newer. +# Requires glibc 2.25 to build, falls back to /dev/random if unavailable. +#CONFIG_GETRANDOM=y + # IEEE 802.11n (High Throughput) support (mainly for AP mode) -#CONFIG_IEEE80211N=y +CONFIG_IEEE80211N=y # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) # (depends on CONFIG_IEEE80211N) -#CONFIG_IEEE80211AC=y +CONFIG_IEEE80211AC=y # Wireless Network Management (IEEE Std 802.11v-2011) # Note: This is experimental and not complete implementation. @@ -462,10 +477,10 @@ CONFIG_PEERKEY=y # This can be used to enable functionality to improve interworking with # external networks (GAS/ANQP to learn more about the networks and network # selection based on available credentials). -#CONFIG_INTERWORKING=y +CONFIG_INTERWORKING=y # Hotspot 2.0 -#CONFIG_HS20=y +CONFIG_HS20=y # Enable interface matching in wpa_supplicant #CONFIG_MATCH_IFACE=y @@ -478,20 +493,20 @@ CONFIG_PEERKEY=y # should be noted that this is mainly aimed at simple cases like # WPA2-Personal while more complex configurations like WPA2-Enterprise with an # external RADIUS server can be supported with hostapd. -#CONFIG_AP=y +CONFIG_AP=y # P2P (Wi-Fi Direct) # This can be used to enable P2P support in wpa_supplicant. See README-P2P for # more information on P2P operations. -#CONFIG_P2P=y +CONFIG_P2P=y # Enable TDLS support #CONFIG_TDLS=y -# Wi-Fi Direct -# This can be used to enable Wi-Fi Direct extensions for P2P using an external +# Wi-Fi Display +# This can be used to enable Wi-Fi Display extensions for P2P using an external # program to control the additional information exchanges in the messages. -#CONFIG_WIFI_DISPLAY=y +CONFIG_WIFI_DISPLAY=y # Autoscan # This can be used to enable automatic scan support in wpa_supplicant. @@ -548,3 +563,40 @@ CONFIG_PEERKEY=y # Support Multi Band Operation #CONFIG_MBO=y + +# Fast Initial Link Setup (FILS) (IEEE 802.11ai) +#CONFIG_FILS=y +# FILS shared key authentication with PFS +#CONFIG_FILS_SK_PFS=y + +# Support RSN on IBSS networks +# This is needed to be able to use mode=1 network profile with proto=RSN and +# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None). +CONFIG_IBSS_RSN=y + +# External PMKSA cache control +# This can be used to enable control interface commands that allow the current +# PMKSA cache entries to be fetched and new entries to be added. +#CONFIG_PMKSA_CACHE_EXTERNAL=y + +# Mesh Networking (IEEE 802.11s) +#CONFIG_MESH=y + +# Background scanning modules +# These can be used to request wpa_supplicant to perform background scanning +# operations for roaming within an ESS (same SSID). See the bgscan parameter in +# the wpa_supplicant.conf file for more details. +# Periodic background scans based on signal strength +CONFIG_BGSCAN_SIMPLE=y +# Learn channels used by the network and try to avoid bgscans on other +# channels (experimental) +#CONFIG_BGSCAN_LEARN=y + +# Opportunistic Wireless Encryption (OWE) +# Experimental implementation of draft-harkins-owe-07.txt +#CONFIG_OWE=y + +# Device Provisioning Protocol (DPP) +# This requires CONFIG_IEEE80211W=y to be enabled, too. (see +# wpa_supplicant/README-DPP for details) +CONFIG_DPP=y diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.c b/contrib/wpa/wpa_supplicant/dpp_supplicant.c new file mode 100644 index 000000000000..e003a8514edb --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.c @@ -0,0 +1,2246 @@ +/* + * wpa_supplicant - DPP + * Copyright (c) 2017, Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/dpp.h" +#include "common/gas.h" +#include "common/gas_server.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/pmksa_cache.h" +#include "wpa_supplicant_i.h" +#include "config.h" +#include "driver_i.h" +#include "offchannel.h" +#include "gas_query.h" +#include "bss.h" +#include "scan.h" +#include "notify.h" +#include "dpp_supplicant.h" + + +static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s, + unsigned int freq); +static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx); +static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator); +static void wpas_dpp_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); +static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); +static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s); +static void +wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result); + +static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +/* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only + * a single transaction in progress at any point in time. */ +static const u8 TRANSACTION_ID = 1; + + +/** + * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code + * @wpa_s: Pointer to wpa_supplicant data + * @cmd: DPP URI read from a QR Code + * Returns: Identifier of the stored info or -1 on failure + */ +int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd) +{ + struct dpp_bootstrap_info *bi; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + bi = dpp_add_qr_code(wpa_s->dpp, cmd); + if (!bi) + return -1; + + if (auth && auth->response_pending && + dpp_notify_new_qr_code(auth, bi) == 1) { + wpa_printf(MSG_DEBUG, + "DPP: Sending out pending authentication response"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(auth->peer_mac_addr), auth->curr_freq, + DPP_PA_AUTHENTICATION_RESP); + offchannel_send_action(wpa_s, auth->curr_freq, + auth->peer_mac_addr, wpa_s->own_addr, + broadcast, + wpabuf_head(auth->resp_msg), + wpabuf_len(auth->resp_msg), + 500, wpas_dpp_tx_status, 0); + } + + return bi->id; +} + + +static void wpas_dpp_auth_resp_retry_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->resp_msg) + return; + + wpa_printf(MSG_DEBUG, + "DPP: Retry Authentication Response after timeout"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(auth->peer_mac_addr), auth->curr_freq, + DPP_PA_AUTHENTICATION_RESP); + offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr, + wpa_s->own_addr, broadcast, + wpabuf_head(auth->resp_msg), + wpabuf_len(auth->resp_msg), + 500, wpas_dpp_tx_status, 0); +} + + +static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + unsigned int wait_time, max_tries; + + if (!auth || !auth->resp_msg) + return; + + if (wpa_s->dpp_resp_max_tries) + max_tries = wpa_s->dpp_resp_max_tries; + else + max_tries = 5; + auth->auth_resp_tries++; + if (auth->auth_resp_tries >= max_tries) { + wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange"); + offchannel_send_action_done(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return; + } + + if (wpa_s->dpp_resp_retry_time) + wait_time = wpa_s->dpp_resp_retry_time; + else + wait_time = 1000; + wpa_printf(MSG_DEBUG, + "DPP: Schedule retransmission of Authentication Response frame in %u ms", + wait_time); + eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); + eloop_register_timeout(wait_time / 1000, + (wait_time % 1000) * 1000, + wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +} + + +static 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->disconnected = 0; + wpa_s->reassociate = 1; + wpa_s->scan_runs = 0; + wpa_s->normal_scans = 0; + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); +} + + +static void wpas_dpp_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) +{ + const char *res_txt; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : + (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : + "FAILED"); + wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR + " result=%s", freq, MAC2STR(dst), res_txt); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR + " freq=%u result=%s", MAC2STR(dst), freq, res_txt); + + if (!wpa_s->dpp_auth) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore TX status since there is no ongoing authentication exchange"); + return; + } + +#ifdef CONFIG_DPP2 + if (auth->connect_on_tx_status) { + wpa_printf(MSG_DEBUG, + "DPP: Try to connect after completed configuration result"); + wpas_dpp_try_to_connect(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return; + } +#endif /* CONFIG_DPP2 */ + + if (wpa_s->dpp_auth->remove_on_tx_status) { + wpa_printf(MSG_DEBUG, + "DPP: Terminate authentication exchange due to an earlier error"); + eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, + NULL); + offchannel_send_action_done(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return; + } + + if (wpa_s->dpp_auth_ok_on_ack) + wpas_dpp_auth_success(wpa_s, 1); + + if (!is_broadcast_ether_addr(dst) && + result != OFFCHANNEL_SEND_ACTION_SUCCESS) { + wpa_printf(MSG_DEBUG, + "DPP: Unicast DPP Action frame was not ACKed"); + if (auth->waiting_auth_resp) { + /* In case of DPP Authentication Request frame, move to + * the next channel immediately. */ + offchannel_send_action_done(wpa_s); + wpas_dpp_auth_init_next(wpa_s); + return; + } + if (auth->waiting_auth_conf) { + wpas_dpp_auth_resp_retry(wpa_s); + return; + } + } + + if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && + result == OFFCHANNEL_SEND_ACTION_SUCCESS) { + /* Allow timeout handling to stop iteration if no response is + * received from a peer that has ACKed a request. */ + auth->auth_req_ack = 1; + } + + if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 && + wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response", + wpa_s->dpp_auth->curr_freq, + wpa_s->dpp_auth->neg_freq); + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq); + } + + if (wpa_s->dpp_auth_ok_on_ack) + wpa_s->dpp_auth_ok_on_ack = 0; +} + + +static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + unsigned int freq; + struct os_reltime now, diff; + unsigned int wait_time, diff_ms; + + if (!auth || !auth->waiting_auth_resp) + return; + + wait_time = wpa_s->dpp_resp_wait_time ? + wpa_s->dpp_resp_wait_time : 2000; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff); + diff_ms = diff.sec * 1000 + diff.usec / 1000; + wpa_printf(MSG_DEBUG, + "DPP: Reply wait timeout - wait_time=%u diff_ms=%u", + wait_time, diff_ms); + + if (auth->auth_req_ack && diff_ms >= wait_time) { + /* Peer ACK'ed Authentication Request frame, but did not reply + * with Authentication Response frame within two seconds. */ + wpa_printf(MSG_INFO, + "DPP: No response received from responder - stopping initiation attempt"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED); + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + dpp_auth_deinit(auth); + wpa_s->dpp_auth = NULL; + return; + } + + if (diff_ms >= wait_time) { + /* Authentication Request frame was not ACK'ed and no reply + * was receiving within two seconds. */ + wpa_printf(MSG_DEBUG, + "DPP: Continue Initiator channel iteration"); + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + wpas_dpp_auth_init_next(wpa_s); + return; + } + + /* Driver did not support 2000 ms long wait_time with TX command, so + * schedule listen operation to continue waiting for the response. + * + * DPP listen operations continue until stopped, so simply schedule a + * new call to this function at the point when the two second reply + * wait has expired. */ + wait_time -= diff_ms; + + freq = auth->curr_freq; + if (auth->neg_freq > 0) + freq = auth->neg_freq; + wpa_printf(MSG_DEBUG, + "DPP: Continue reply wait on channel %u MHz for %u ms", + freq, wait_time); + wpa_s->dpp_in_response_listen = 1; + wpas_dpp_listen_start(wpa_s, freq); + + eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, + wpas_dpp_reply_wait_timeout, wpa_s, NULL); +} + + +static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth) +{ +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->dpp_config_obj_override) + auth->config_obj_override = + os_strdup(wpa_s->dpp_config_obj_override); + if (wpa_s->dpp_discovery_override) + auth->discovery_override = + os_strdup(wpa_s->dpp_discovery_override); + if (wpa_s->dpp_groups_override) + auth->groups_override = + os_strdup(wpa_s->dpp_groups_override); + auth->ignore_netaccesskey_mismatch = + wpa_s->dpp_ignore_netaccesskey_mismatch; +#endif /* CONFIG_TESTING_OPTIONS */ +} + + +static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (!wpa_s->dpp_auth) + return; + wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout"); + wpas_dpp_auth_init_next(wpa_s); +} + + +static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + const u8 *dst; + unsigned int wait_time, max_wait_time, freq, max_tries, used; + struct os_reltime now, diff; + + wpa_s->dpp_in_response_listen = 0; + if (!auth) + return -1; + + if (auth->freq_idx == 0) + os_get_reltime(&wpa_s->dpp_init_iter_start); + + if (auth->freq_idx >= auth->num_freq) { + auth->num_freq_iters++; + if (wpa_s->dpp_init_max_tries) + max_tries = wpa_s->dpp_init_max_tries; + else + max_tries = 5; + if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) { + wpa_printf(MSG_INFO, + "DPP: No response received from responder - stopping initiation attempt"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED); + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, + wpa_s, NULL); + offchannel_send_action_done(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return -1; + } + auth->freq_idx = 0; + eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); + if (wpa_s->dpp_init_retry_time) + wait_time = wpa_s->dpp_init_retry_time; + else + wait_time = 10000; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff); + used = diff.sec * 1000 + diff.usec / 1000; + if (used > wait_time) + wait_time = 0; + else + wait_time -= used; + wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms", + wait_time); + eloop_register_timeout(wait_time / 1000, + (wait_time % 1000) * 1000, + wpas_dpp_init_timeout, wpa_s, + NULL); + return 0; + } + freq = auth->freq[auth->freq_idx++]; + auth->curr_freq = freq; + + if (is_zero_ether_addr(auth->peer_bi->mac_addr)) + dst = broadcast; + else + dst = auth->peer_bi->mac_addr; + wpa_s->dpp_auth_ok_on_ack = 0; + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + wait_time = wpa_s->max_remain_on_chan; + max_wait_time = wpa_s->dpp_resp_wait_time ? + wpa_s->dpp_resp_wait_time : 2000; + if (wait_time > max_wait_time) + wait_time = max_wait_time; + wait_time += 10; /* give the driver some extra time to complete */ + eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, + wpas_dpp_reply_wait_timeout, + wpa_s, NULL); + wait_time -= 10; + if (auth->neg_freq > 0 && freq != auth->neg_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response", + freq, auth->neg_freq); + } + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ); + auth->auth_req_ack = 0; + os_get_reltime(&wpa_s->dpp_last_init); + return offchannel_send_action(wpa_s, freq, dst, + wpa_s->own_addr, broadcast, + wpabuf_head(auth->req_msg), + wpabuf_len(auth->req_msg), + wait_time, wpas_dpp_tx_status, 0); +} + + +int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi = NULL; + u8 allowed_roles = DPP_CAPAB_CONFIGURATOR; + unsigned int neg_freq = 0; + + wpa_s->dpp_gas_client = 0; + + pos = os_strstr(cmd, " peer="); + if (!pos) + return -1; + pos += 6; + peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Could not find bootstrapping info for the identified peer"); + return -1; + } + + pos = os_strstr(cmd, " own="); + if (pos) { + pos += 5; + own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!own_bi) { + wpa_printf(MSG_INFO, + "DPP: Could not find bootstrapping info for the identified local entry"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)", + peer_bi->curve->name, own_bi->curve->name); + return -1; + } + } + + pos = os_strstr(cmd, " role="); + if (pos) { + pos += 6; + if (os_strncmp(pos, "configurator", 12) == 0) + allowed_roles = DPP_CAPAB_CONFIGURATOR; + else if (os_strncmp(pos, "enrollee", 8) == 0) + allowed_roles = DPP_CAPAB_ENROLLEE; + else if (os_strncmp(pos, "either", 6) == 0) + allowed_roles = DPP_CAPAB_CONFIGURATOR | + DPP_CAPAB_ENROLLEE; + else + goto fail; + } + + pos = os_strstr(cmd, " netrole="); + if (pos) { + pos += 9; + wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0; + } + + pos = os_strstr(cmd, " neg_freq="); + if (pos) + neg_freq = atoi(pos + 10); + + if (wpa_s->dpp_auth) { + eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, + NULL); + offchannel_send_action_done(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + } + wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, 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; + goto fail; + } + + wpa_s->dpp_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); + + return wpas_dpp_auth_init_next(wpa_s); +fail: + return -1; +} + + +struct wpas_dpp_listen_work { + unsigned int freq; + unsigned int duration; + struct wpabuf *probe_resp_ie; +}; + + +static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork) +{ + if (!lwork) + return; + os_free(lwork); +} + + +static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpas_dpp_listen_work *lwork; + + if (!wpa_s->dpp_listen_work) + return; + + lwork = wpa_s->dpp_listen_work->ctx; + wpas_dpp_listen_work_free(lwork); + radio_work_done(wpa_s->dpp_listen_work); + wpa_s->dpp_listen_work = NULL; +} + + +static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpas_dpp_listen_work *lwork = work->ctx; + + if (deinit) { + if (work->started) { + wpa_s->dpp_listen_work = NULL; + wpas_dpp_listen_stop(wpa_s); + } + wpas_dpp_listen_work_free(lwork); + return; + } + + wpa_s->dpp_listen_work = work; + + wpa_s->dpp_pending_listen_freq = lwork->freq; + + if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, + wpa_s->max_remain_on_chan) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to request the driver to remain on channel (%u MHz) for listen", + lwork->freq); + wpa_s->dpp_listen_freq = 0; + wpas_dpp_listen_work_done(wpa_s); + wpa_s->dpp_pending_listen_freq = 0; + return; + } + wpa_s->off_channel_freq = 0; + wpa_s->roc_waiting_drv_freq = lwork->freq; +} + + +static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s, + unsigned int freq) +{ + struct wpas_dpp_listen_work *lwork; + + if (wpa_s->dpp_listen_work) { + wpa_printf(MSG_DEBUG, + "DPP: Reject start_listen since dpp_listen_work already exists"); + return -1; + } + + if (wpa_s->dpp_listen_freq) + wpas_dpp_listen_stop(wpa_s); + wpa_s->dpp_listen_freq = freq; + + lwork = os_zalloc(sizeof(*lwork)); + if (!lwork) + return -1; + lwork->freq = freq; + + if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb, + lwork) < 0) { + wpas_dpp_listen_work_free(lwork); + return -1; + } + + return 0; +} + + +int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int freq; + + freq = atoi(cmd); + if (freq <= 0) + return -1; + + if (os_strstr(cmd, " role=configurator")) + wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR; + else if (os_strstr(cmd, " role=enrollee")) + wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + else + 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 (wpa_s->dpp_listen_freq == (unsigned int) freq) { + wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz", + freq); + return 0; + } + + return wpas_dpp_listen_start(wpa_s, freq); +} + + +void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s) +{ + wpa_s->dpp_in_response_listen = 0; + if (!wpa_s->dpp_listen_freq) + return; + + wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz", + wpa_s->dpp_listen_freq); + wpa_drv_cancel_remain_on_channel(wpa_s); + wpa_s->dpp_listen_freq = 0; + wpas_dpp_listen_work_done(wpa_s); +} + + +void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, + unsigned int freq) +{ + wpas_dpp_listen_work_done(wpa_s); + + if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) { + unsigned int new_freq; + + /* Continue listen with a new remain-on-channel */ + if (wpa_s->dpp_auth->neg_freq > 0) + new_freq = wpa_s->dpp_auth->neg_freq; + else + new_freq = wpa_s->dpp_auth->curr_freq; + wpa_printf(MSG_DEBUG, + "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session", + new_freq); + wpas_dpp_listen_start(wpa_s, new_freq); + return; + } + + if (wpa_s->dpp_listen_freq) { + /* Continue listen with a new remain-on-channel */ + wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq); + } +} + + +static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + const u8 *r_bootstrap, *i_bootstrap; + u16 r_bootstrap_len, i_bootstrap_len; + struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL; + + if (!wpa_s->dpp) + return; + + wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR, + MAC2STR(src)); + + 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); + + 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_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "Missing or invalid required Initiator Bootstrapping Key Hash attribute"); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", + i_bootstrap, i_bootstrap_len); + + /* Try to find own and peer bootstrapping key matches based on the + * received hash values */ + dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap, + &own_bi, &peer_bi); + if (!own_bi) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "No matching own bootstrapping key found - ignore message"); + return; + } + + if (wpa_s->dpp_auth) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "Already in DPP authentication exchange - ignore new one"); + return; + } + + 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_qr_mutual, + peer_bi, own_bi, freq, hdr, buf, len); + if (!wpa_s->dpp_auth) { + wpa_printf(MSG_DEBUG, "DPP: No response generated"); + return; + } + wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth); + if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth, + wpa_s->dpp_configurator_params) < 0) { + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return; + } + os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN); + + if (wpa_s->dpp_listen_freq && + wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Stop listen on %u MHz to allow response on the request %u MHz", + wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq); + wpas_dpp_listen_stop(wpa_s); + } + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), wpa_s->dpp_auth->curr_freq, + DPP_PA_AUTHENTICATION_RESP); + offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq, + src, wpa_s->own_addr, broadcast, + wpabuf_head(wpa_s->dpp_auth->resp_msg), + wpabuf_len(wpa_s->dpp_auth->resp_msg), + 500, wpas_dpp_tx_status, 0); +} + + +static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s) +{ + /* TODO: stop wait and start ROC */ +} + + +static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth) +{ + struct wpa_ssid *ssid; + +#ifdef CONFIG_DPP2 + if (auth->akm == DPP_AKM_SAE) { +#ifdef CONFIG_SAE + struct wpa_driver_capa capa; + int res; + + res = wpa_drv_get_capa(wpa_s, &capa); + if (res == 0 && + !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) { + wpa_printf(MSG_DEBUG, + "DPP: SAE not supported by the driver"); + return NULL; + } +#else /* CONFIG_SAE */ + wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build"); + return NULL; +#endif /* CONFIG_SAE */ + } +#endif /* CONFIG_DPP2 */ + + ssid = wpa_config_add_network(wpa_s->conf); + if (!ssid) + return NULL; + wpas_notify_network_added(wpa_s, ssid); + wpa_config_set_network_defaults(ssid); + ssid->disabled = 1; + + ssid->ssid = os_malloc(auth->ssid_len); + if (!ssid->ssid) + goto fail; + os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len); + ssid->ssid_len = auth->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 (!ssid->dpp_connector) + goto fail; + } + + if (auth->c_sign_key) { + ssid->dpp_csign = os_malloc(wpabuf_len(auth->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); + } + + if (auth->net_access_key) { + ssid->dpp_netaccesskey = + os_malloc(wpabuf_len(auth->net_access_key)); + if (!ssid->dpp_netaccesskey) + goto fail; + os_memcpy(ssid->dpp_netaccesskey, + wpabuf_head(auth->net_access_key), + wpabuf_len(auth->net_access_key)); + ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key); + 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) + ssid->key_mgmt = 0; + if (dpp_akm_psk(auth->akm)) + ssid->key_mgmt |= WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK; + if (dpp_akm_sae(auth->akm)) + ssid->key_mgmt |= WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_FT_SAE; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; + if (auth->passphrase[0]) { + if (wpa_config_set_quoted(ssid, "psk", + auth->passphrase) < 0) + 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); + } + } + + return ssid; +fail: + wpas_notify_network_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + return NULL; +} + + +static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth) +{ + struct wpa_ssid *ssid; + + if (wpa_s->conf->dpp_config_processing < 1) + return 0; + + ssid = wpas_dpp_add_network(wpa_s, auth); + if (!ssid) + return -1; + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id); + if (wpa_s->conf->dpp_config_processing == 2) + ssid->disabled = 0; + +#ifndef CONFIG_NO_CONFIG_WRITE + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) + wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration"); +#endif /* CONFIG_NO_CONFIG_WRITE */ + + if (wpa_s->conf->dpp_config_processing < 2) + return 0; + +#ifdef CONFIG_DPP2 + if (auth->peer_version >= 2) { + wpa_printf(MSG_DEBUG, + "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result"); + auth->connect_on_tx_status = 1; + return 0; + } +#endif /* CONFIG_DPP2 */ + + wpas_dpp_try_to_connect(wpa_s); + return 0; +} + + +static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth) +{ + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED); + if (auth->ssid_len) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s", + wpa_ssid_txt(auth->ssid, auth->ssid_len)); + if (auth->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); + } + if (auth->c_sign_key) { + char *hex; + size_t hexlen; + + hexlen = 2 * wpabuf_len(auth->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)); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s", + hex); + os_free(hex); + } + } + if (auth->net_access_key) { + char *hex; + size_t hexlen; + + hexlen = 2 * wpabuf_len(auth->net_access_key) + 1; + hex = os_malloc(hexlen); + if (hex) { + wpa_snprintf_hex(hex, hexlen, + wpabuf_head(auth->net_access_key), + wpabuf_len(auth->net_access_key)); + if (auth->net_access_key_expiry) + wpa_msg(wpa_s, MSG_INFO, + DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex, + (long unsigned) + auth->net_access_key_expiry); + else + wpa_msg(wpa_s, MSG_INFO, + DPP_EVENT_NET_ACCESS_KEY "%s", hex); + os_free(hex); + } + } + + return wpas_dpp_process_config(wpa_s, auth); +} + + +static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, + enum gas_query_result result, + const struct wpabuf *adv_proto, + const struct wpabuf *resp, u16 status_code) +{ + struct wpa_supplicant *wpa_s = ctx; + const u8 *pos; + struct dpp_authentication *auth = wpa_s->dpp_auth; + int res; + enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; + + wpa_s->dpp_gas_dialog_token = -1; + + if (!auth || !auth->auth_success) { + wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); + return; + } + if (result != GAS_QUERY_SUCCESS || + !resp || status_code != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed"); + goto fail; + } + + wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto", + adv_proto); + wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)", + resp); + + if (wpabuf_len(adv_proto) != 10 || + !(pos = wpabuf_head(adv_proto)) || + pos[0] != WLAN_EID_ADV_PROTO || + pos[1] != 8 || + pos[3] != WLAN_EID_VENDOR_SPECIFIC || + pos[4] != 5 || + WPA_GET_BE24(&pos[5]) != OUI_WFA || + pos[8] != 0x1a || + pos[9] != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Not a DPP Advertisement Protocol ID"); + goto fail; + } + + if (dpp_conf_resp_rx(auth, resp) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); + goto fail; + } + + res = wpas_dpp_handle_config_obj(wpa_s, auth); + if (res < 0) + goto fail; + + status = DPP_STATUS_OK; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_REJECT_CONFIG) { + wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object"); + status = DPP_STATUS_CONFIG_REJECTED; + } +#endif /* CONFIG_TESTING_OPTIONS */ +fail: + if (status != DPP_STATUS_OK) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); +#ifdef CONFIG_DPP2 + if (auth->peer_version >= 2 && + auth->conf_resp_status == DPP_STATUS_OK) { + struct wpabuf *msg; + + wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); + msg = dpp_build_conf_result(auth, status); + if (!msg) + goto fail2; + + wpa_msg(wpa_s, MSG_INFO, + DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(addr), auth->curr_freq, + DPP_PA_CONFIGURATION_RESULT); + offchannel_send_action(wpa_s, auth->curr_freq, + addr, wpa_s->own_addr, broadcast, + wpabuf_head(msg), + wpabuf_len(msg), + 500, wpas_dpp_tx_status, 0); + wpabuf_free(msg); + + /* This exchange will be terminated in the TX status handler */ + return; + } +fail2: +#endif /* CONFIG_DPP2 */ + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; +} + + +static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + struct wpabuf *buf; + char json[100]; + int res; + + 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); + if (!buf) { + wpa_printf(MSG_DEBUG, + "DPP: No configuration request data available"); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)", + MAC2STR(auth->peer_mac_addr), auth->curr_freq); + + res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq, + 1, buf, wpas_dpp_gas_resp_cb, wpa_s); + if (res < 0) { + wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request"); + wpabuf_free(buf); + } else { + wpa_printf(MSG_DEBUG, + "DPP: GAS query started with dialog token %u", res); + wpa_s->dpp_gas_dialog_token = res; + } +} + + +static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator) +{ + wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); + wpa_msg(wpa_s, 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 (wpa_s->dpp_auth->configurator) { + /* Prevent GAS response */ + wpa_s->dpp_auth->auth_success = 0; + } + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + if (wpa_s->dpp_auth->configurator) + wpas_dpp_start_gas_server(wpa_s); + else + wpas_dpp_start_gas_client(wpa_s); +} + + +static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + struct wpabuf *msg; + + wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR + " (freq %u MHz)", MAC2STR(src), freq); + + if (!auth) { + wpa_printf(MSG_DEBUG, + "DPP: No DPP Authentication in progress - drop"); + return; + } + + if (!is_zero_ether_addr(auth->peer_mac_addr) && + os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " + MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); + return; + } + + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + + if (auth->curr_freq != freq && auth->neg_freq == freq) { + wpa_printf(MSG_DEBUG, + "DPP: Responder accepted request for different negotiation channel"); + auth->curr_freq = freq; + } + + eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); + msg = dpp_auth_resp_rx(auth, hdr, buf, len); + if (!msg) { + if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { + wpa_printf(MSG_DEBUG, + "DPP: Start wait for full response"); + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_start(wpa_s, auth->curr_freq); + return; + } + wpa_printf(MSG_DEBUG, "DPP: No confirm generated"); + return; + } + os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF); + offchannel_send_action(wpa_s, auth->curr_freq, + src, wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + 500, wpas_dpp_tx_status, 0); + wpabuf_free(msg); + wpa_s->dpp_auth_ok_on_ack = 1; +} + + +static void wpas_dpp_rx_auth_conf(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; + + wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR, + MAC2STR(src)); + + if (!auth) { + wpa_printf(MSG_DEBUG, + "DPP: No DPP Authentication in progress - drop"); + return; + } + + if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " + MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); + return; + } + + if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); + return; + } + + wpas_dpp_auth_success(wpa_s, 0); +} + + +#ifdef CONFIG_DPP2 + +static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth || !auth->waiting_conf_result) + return; + + wpa_printf(MSG_DEBUG, + "DPP: Timeout while waiting for Configuration Result"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(auth); + wpa_s->dpp_auth = NULL; +} + + +static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + enum dpp_status_error status; + + wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR, + MAC2STR(src)); + + if (!auth || !auth->waiting_conf_result) { + wpa_printf(MSG_DEBUG, + "DPP: No DPP Configuration waiting for result - drop"); + return; + } + + if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " + MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); + return; + } + + status = dpp_conf_result_rx(auth, hdr, buf, len); + + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + if (status == DPP_STATUS_OK) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); + else + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(auth); + wpa_s->dpp_auth = NULL; + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); +} + +#endif /* CONFIG_DPP2 */ + + +static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, + const u8 *src, + const u8 *buf, size_t len) +{ + struct wpa_ssid *ssid; + const u8 *connector, *trans_id, *status; + u16 connector_len, trans_id_len, status_len; + struct dpp_introduction intro; + struct rsn_pmksa_cache_entry *entry; + struct os_time now; + struct os_reltime rnow; + os_time_t expiry; + unsigned int seconds; + enum dpp_status_error res; + + wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR, + MAC2STR(src)); + if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) || + os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from " + MACSTR " - drop", MAC2STR(src)); + return; + } + offchannel_send_action_done(wpa_s); + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (ssid == wpa_s->dpp_intro_network) + break; + } + if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey || + !ssid->dpp_csign) { + wpa_printf(MSG_DEBUG, + "DPP: Profile not found for network introduction"); + return; + } + + trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, + &trans_id_len); + if (!trans_id || trans_id_len != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include Transaction ID"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_transaction_id", MAC2STR(src)); + goto fail; + } + if (trans_id[0] != TRANSACTION_ID) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore frame with unexpected Transaction ID %u", + trans_id[0]); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=transaction_id_mismatch", MAC2STR(src)); + goto fail; + } + + status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len); + if (!status || status_len != 1) { + wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_status", MAC2STR(src)); + goto fail; + } + if (status[0] != DPP_STATUS_OK) { + wpa_printf(MSG_DEBUG, + "DPP: Peer rejected network introduction: Status %u", + status[0]); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " status=%u", MAC2STR(src), status[0]); + goto fail; + } + + connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len); + if (!connector) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include its Connector"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_connector", MAC2STR(src)); + goto fail; + } + + res = dpp_peer_intro(&intro, ssid->dpp_connector, + ssid->dpp_netaccesskey, + ssid->dpp_netaccesskey_len, + ssid->dpp_csign, + ssid->dpp_csign_len, + connector, connector_len, &expiry); + if (res != DPP_STATUS_OK) { + wpa_printf(MSG_INFO, + "DPP: Network Introduction protocol resulted in failure"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=peer_connector_validation_failed", MAC2STR(src)); + goto fail; + } + + entry = os_zalloc(sizeof(*entry)); + if (!entry) + goto fail; + os_memcpy(entry->aa, src, ETH_ALEN); + os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN); + os_memcpy(entry->pmk, intro.pmk, intro.pmk_len); + entry->pmk_len = intro.pmk_len; + entry->akmp = WPA_KEY_MGMT_DPP; + if (expiry) { + os_get_time(&now); + seconds = expiry - now.sec; + } else { + seconds = 86400 * 7; + } + os_get_reltime(&rnow); + entry->expiration = rnow.sec + seconds; + entry->reauth_time = rnow.sec + seconds; + entry->network_ctx = ssid; + wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " status=%u", MAC2STR(src), status[0]); + + wpa_printf(MSG_DEBUG, + "DPP: Try connection again after successful network introduction"); + if (wpa_supplicant_fast_associate(wpa_s) != 1) { + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } +fail: + os_memset(&intro, 0, sizeof(intro)); +} + + +static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq) +{ + int i, j; + + if (!wpa_s->hw.modes) + return -1; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; + + for (j = 0; j < mode->num_channels; j++) { + struct hostapd_channel_data *chan = &mode->channels[j]; + + if (chan->freq != (int) freq) + continue; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_NO_IR | + HOSTAPD_CHAN_RADAR)) + continue; + + return 1; + } + } + + wpa_printf(MSG_DEBUG, + "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list", + freq); + + return 0; +} + + +static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s, + struct dpp_pkex *pkex) +{ + if (pkex->freq == 2437) + pkex->freq = 5745; + else if (pkex->freq == 5745) + pkex->freq = 5220; + else if (pkex->freq == 5220) + pkex->freq = 60480; + else + return -1; /* no more channels to try */ + + if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) { + wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz", + pkex->freq); + return 0; + } + + /* Could not use this channel - try the next one */ + return wpas_dpp_pkex_next_channel(wpa_s, pkex); +} + + +static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; + + if (!pkex || !pkex->exchange_req) + return; + if (pkex->exch_req_tries >= 5) { + if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "No response from PKEX peer"); + dpp_pkex_free(pkex); + wpa_s->dpp_pkex = NULL; + return; + } + pkex->exch_req_tries = 0; + } + + pkex->exch_req_tries++; + wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", + pkex->exch_req_tries); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ); + offchannel_send_action(wpa_s, pkex->freq, broadcast, + wpa_s->own_addr, broadcast, + wpabuf_head(pkex->exchange_req), + wpabuf_len(pkex->exchange_req), + pkex->exch_req_wait_time, + wpas_dpp_tx_pkex_status, 0); +} + + +static void +wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result) +{ + const char *res_txt; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; + + res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : + (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : + "FAILED"); + wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR + " result=%s (PKEX)", + freq, MAC2STR(dst), res_txt); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR + " freq=%u result=%s", MAC2STR(dst), freq, res_txt); + + if (!pkex) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore TX status since there is no ongoing PKEX exchange"); + return; + } + + if (pkex->failed) { + wpa_printf(MSG_DEBUG, + "DPP: Terminate PKEX exchange due to an earlier error"); + if (pkex->t > pkex->own_bi->pkex_t) + pkex->own_bi->pkex_t = pkex->t; + dpp_pkex_free(pkex); + wpa_s->dpp_pkex = NULL; + return; + } + + if (pkex->exch_req_wait_time && pkex->exchange_req) { + /* Wait for PKEX Exchange Response frame and retry request if + * no response is seen. */ + eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); + eloop_register_timeout(pkex->exch_req_wait_time / 1000, + (pkex->exch_req_wait_time % 1000) * 1000, + wpas_dpp_pkex_retry_timeout, wpa_s, + NULL); + } +} + + +static void +wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *buf, size_t len, unsigned int freq) +{ + struct wpabuf *msg; + unsigned int wait_time; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR, + MAC2STR(src)); + + /* TODO: Support multiple PKEX codes by iterating over all the enabled + * values here */ + + if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) { + wpa_printf(MSG_DEBUG, + "DPP: No PKEX code configured - ignore request"); + return; + } + + if (wpa_s->dpp_pkex) { + /* TODO: Support parallel operations */ + wpa_printf(MSG_DEBUG, + "DPP: Already in PKEX session - ignore new request"); + return; + } + + wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi, + wpa_s->own_addr, src, + wpa_s->dpp_pkex_identifier, + wpa_s->dpp_pkex_code, + buf, len); + if (!wpa_s->dpp_pkex) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to process the request - ignore it"); + return; + } + + msg = wpa_s->dpp_pkex->exchange_resp; + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP); + offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, + broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); +} + + +static void +wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *buf, size_t len, unsigned int freq) +{ + struct wpabuf *msg; + unsigned int wait_time; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR, + MAC2STR(src)); + + /* TODO: Support multiple PKEX codes by iterating over all the enabled + * values here */ + + if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator || + wpa_s->dpp_pkex->exchange_done) { + wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); + return; + } + + eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); + wpa_s->dpp_pkex->exch_req_wait_time = 0; + + msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len); + if (!msg) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR, + MAC2STR(src)); + + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ); + offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, + broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); + wpabuf_free(msg); +} + + +static struct dpp_bootstrap_info * +wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer, + unsigned int freq) +{ + struct dpp_bootstrap_info *bi; + + bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq); + if (!bi) + return NULL; + wpa_s->dpp_pkex = NULL; + return bi; +} + + +static void +wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + struct wpabuf *msg; + unsigned int wait_time; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR, + MAC2STR(src)); + + if (!pkex || pkex->initiator || !pkex->exchange_done) { + wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); + return; + } + + msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len); + if (!msg) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); + if (pkex->failed) { + wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange"); + if (pkex->t > pkex->own_bi->pkex_t) + pkex->own_bi->pkex_t = pkex->t; + dpp_pkex_free(wpa_s->dpp_pkex); + wpa_s->dpp_pkex = NULL; + } + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to " + MACSTR, MAC2STR(src)); + + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP); + offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, + broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); + wpabuf_free(msg); + + wpas_dpp_pkex_finish(wpa_s, src, freq); +} + + +static void +wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + int res; + struct dpp_bootstrap_info *bi; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; + char cmd[500]; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR, + MAC2STR(src)); + + if (!pkex || !pkex->initiator || !pkex->exchange_done) { + wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); + return; + } + + res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); + if (res < 0) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); + return; + } + + bi = wpas_dpp_pkex_finish(wpa_s, src, freq); + if (!bi) + return; + + os_snprintf(cmd, sizeof(cmd), " peer=%u %s", + bi->id, + wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : ""); + wpa_printf(MSG_DEBUG, + "DPP: Start authentication after PKEX with parameters: %s", + cmd); + if (wpas_dpp_auth_init(wpa_s, cmd) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Authentication initialization failed"); + return; + } +} + + +void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *buf, size_t len, unsigned int freq) +{ + u8 crypto_suite; + enum dpp_public_action_frame_type type; + const u8 *hdr; + unsigned int pkex_t; + + if (len < DPP_HDR_LEN) + return; + if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE) + return; + hdr = buf; + buf += 4; + len -= 4; + crypto_suite = *buf++; + type = *buf++; + len -= 2; + + wpa_printf(MSG_DEBUG, + "DPP: Received DPP Public Action frame crypto suite %u type %d from " + MACSTR " freq=%u", + crypto_suite, type, MAC2STR(src), freq); + if (crypto_suite != 1) { + wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u", + crypto_suite); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR + " freq=%u type=%d ignore=unsupported-crypto-suite", + MAC2STR(src), freq, type); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len); + if (dpp_check_attrs(buf, len) < 0) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR + " freq=%u type=%d ignore=invalid-attributes", + MAC2STR(src), freq, type); + return; + } + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d", + MAC2STR(src), freq, type); + + switch (type) { + case DPP_PA_AUTHENTICATION_REQ: + wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq); + break; + case DPP_PA_AUTHENTICATION_RESP: + wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq); + break; + case DPP_PA_AUTHENTICATION_CONF: + wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len); + break; + case DPP_PA_PEER_DISCOVERY_RESP: + wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len); + break; + case DPP_PA_PKEX_EXCHANGE_REQ: + wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq); + break; + case DPP_PA_PKEX_EXCHANGE_RESP: + wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq); + break; + case DPP_PA_PKEX_COMMIT_REVEAL_REQ: + wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len, + freq); + break; + case DPP_PA_PKEX_COMMIT_REVEAL_RESP: + wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len, + freq); + break; +#ifdef CONFIG_DPP2 + case DPP_PA_CONFIGURATION_RESULT: + wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len); + break; +#endif /* CONFIG_DPP2 */ + default: + wpa_printf(MSG_DEBUG, + "DPP: Ignored unsupported frame subtype %d", type); + break; + } + + if (wpa_s->dpp_pkex) + pkex_t = wpa_s->dpp_pkex->t; + else if (wpa_s->dpp_pkex_bi) + pkex_t = wpa_s->dpp_pkex_bi->pkex_t; + else + pkex_t = 0; + if (pkex_t >= PKEX_COUNTER_T_LIMIT) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0"); + wpas_dpp_pkex_remove(wpa_s, "*"); + } +} + + +static struct wpabuf * +wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query, + size_t query_len) +{ + struct wpa_supplicant *wpa_s = ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + struct wpabuf *resp; + + 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) { + wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); + return NULL; + } + wpa_hexdump(MSG_DEBUG, + "DPP: Received Configuration Request (GAS Query Request)", + query, query_len); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR, + MAC2STR(sa)); + resp = dpp_conf_req_rx(auth, query, query_len); + if (!resp) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + auth->conf_resp = resp; + return resp; +} + + +static void +wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) +{ + struct wpa_supplicant *wpa_s = ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth) { + wpabuf_free(resp); + return; + } + if (auth->conf_resp != resp) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore GAS status report (ok=%d) for unknown response", + ok); + wpabuf_free(resp); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", + ok); + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + if (ok && auth->peer_version >= 2 && + auth->conf_resp_status == DPP_STATUS_OK) { + wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); + auth->waiting_conf_result = 1; + auth->conf_resp = NULL; + wpabuf_free(resp); + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, + wpa_s, NULL); + eloop_register_timeout(2, 0, + wpas_dpp_config_result_wait_timeout, + wpa_s, NULL); + return; + } +#endif /* CONFIG_DPP2 */ + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + if (ok) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); + else + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + wpabuf_free(resp); +} + + +int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd) +{ + struct dpp_authentication *auth; + int ret = -1; + char *curve = NULL; + + auth = os_zalloc(sizeof(*auth)); + 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 && + dpp_configurator_own_config(auth, curve, 0) == 0) + ret = wpas_dpp_handle_config_obj(wpa_s, auth); + + dpp_auth_deinit(auth); + os_free(curve); + + return ret; +} + + +static void +wpas_dpp_tx_introduction_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) +{ + const char *res_txt; + + res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : + (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : + "FAILED"); + wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR + " result=%s (DPP Peer Discovery Request)", + freq, MAC2STR(dst), res_txt); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR + " freq=%u result=%s", MAC2STR(dst), freq, res_txt); + /* TODO: Time out wait for response more quickly in error cases? */ +} + + +int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_bss *bss) +{ + struct os_time now; + struct wpabuf *msg; + unsigned int wait_time; + const u8 *rsn; + struct wpa_ie_data ied; + + if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss) + return 0; /* Not using DPP AKM - continue */ + rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && + !(ied.key_mgmt & WPA_KEY_MGMT_DPP)) + return 0; /* AP does not support DPP AKM - continue */ + if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid)) + return 0; /* PMKSA exists for DPP AKM - continue */ + + if (!ssid->dpp_connector || !ssid->dpp_netaccesskey || + !ssid->dpp_csign) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR + "missing %s", + !ssid->dpp_connector ? "Connector" : + (!ssid->dpp_netaccesskey ? "netAccessKey" : + "C-sign-key")); + return -1; + } + + os_get_time(&now); + + if (ssid->dpp_netaccesskey_expiry && + (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR + "netAccessKey expired"); + return -1; + } + + wpa_printf(MSG_DEBUG, + "DPP: Starting network introduction protocol to derive PMKSA for " + MACSTR, MAC2STR(bss->bssid)); + + msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, + 5 + 4 + os_strlen(ssid->dpp_connector)); + if (!msg) + return -1; + +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID"); + goto skip_trans_id; + } + if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID"); + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 0); + goto skip_trans_id; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + /* Transaction ID */ + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, TRANSACTION_ID); + +#ifdef CONFIG_TESTING_OPTIONS +skip_trans_id: + if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - no Connector"); + goto skip_connector; + } + if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) { + char *connector; + + wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector"); + connector = dpp_corrupt_connector_signature( + ssid->dpp_connector); + if (!connector) { + wpabuf_free(msg); + return -1; + } + wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); + wpabuf_put_le16(msg, os_strlen(connector)); + wpabuf_put_str(msg, connector); + os_free(connector); + goto skip_connector; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + /* DPP Connector */ + wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); + wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector)); + wpabuf_put_str(msg, ssid->dpp_connector); + +#ifdef CONFIG_TESTING_OPTIONS +skip_connector: +#endif /* CONFIG_TESTING_OPTIONS */ + + /* TODO: Timeout on AP response */ + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ); + offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr, + broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_introduction_status, 0); + wpabuf_free(msg); + + /* Request this connection attempt to terminate - new one will be + * started when network introduction protocol completes */ + os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN); + wpa_s->dpp_intro_network = ssid; + return 1; +} + + +int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) +{ + struct dpp_bootstrap_info *own_bi; + const char *pos, *end; + unsigned int wait_time; + + 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) { + wpa_printf(MSG_DEBUG, + "DPP: Identified bootstrap info not found"); + return -1; + } + if (own_bi->type != DPP_BOOTSTRAP_PKEX) { + wpa_printf(MSG_DEBUG, + "DPP: Identified bootstrap info not for PKEX"); + return -1; + } + wpa_s->dpp_pkex_bi = own_bi; + own_bi->pkex_t = 0; /* clear pending errors on new code */ + + os_free(wpa_s->dpp_pkex_identifier); + wpa_s->dpp_pkex_identifier = NULL; + pos = os_strstr(cmd, " identifier="); + if (pos) { + pos += 12; + end = os_strchr(pos, ' '); + if (!end) + return -1; + wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1); + if (!wpa_s->dpp_pkex_identifier) + return -1; + os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos); + wpa_s->dpp_pkex_identifier[end - pos] = '\0'; + } + + pos = os_strstr(cmd, " code="); + if (!pos) + return -1; + os_free(wpa_s->dpp_pkex_code); + wpa_s->dpp_pkex_code = os_strdup(pos + 6); + if (!wpa_s->dpp_pkex_code) + return -1; + + if (os_strstr(cmd, " init=1")) { + struct dpp_pkex *pkex; + struct wpabuf *msg; + + wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); + dpp_pkex_free(wpa_s->dpp_pkex); + wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr, + wpa_s->dpp_pkex_identifier, + wpa_s->dpp_pkex_code); + pkex = wpa_s->dpp_pkex; + if (!pkex) + return -1; + + msg = pkex->exchange_req; + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + pkex->freq = 2437; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, + DPP_PA_PKEX_EXCHANGE_REQ); + offchannel_send_action(wpa_s, pkex->freq, broadcast, + wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); + if (wait_time == 0) + wait_time = 2000; + pkex->exch_req_wait_time = wait_time; + pkex->exch_req_tries = 1; + } + + /* TODO: Support multiple PKEX info entries */ + + os_free(wpa_s->dpp_pkex_auth_cmd); + wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd); + + return 1; +} + + +int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id) +{ + unsigned int id_val; + + if (os_strcmp(id, "*") == 0) { + id_val = 0; + } else { + id_val = atoi(id); + if (id_val == 0) + return -1; + } + + if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code) + return -1; + + /* TODO: Support multiple PKEX entries */ + os_free(wpa_s->dpp_pkex_code); + wpa_s->dpp_pkex_code = NULL; + os_free(wpa_s->dpp_pkex_identifier); + wpa_s->dpp_pkex_identifier = NULL; + os_free(wpa_s->dpp_pkex_auth_cmd); + wpa_s->dpp_pkex_auth_cmd = NULL; + wpa_s->dpp_pkex_bi = NULL; + /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */ + dpp_pkex_free(wpa_s->dpp_pkex); + wpa_s->dpp_pkex = NULL; + return 0; +} + + +void wpas_dpp_stop(struct wpa_supplicant *wpa_s) +{ + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + dpp_pkex_free(wpa_s->dpp_pkex); + wpa_s->dpp_pkex = NULL; + if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0) + gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token); +} + + +int wpas_dpp_init(struct wpa_supplicant *wpa_s) +{ + u8 adv_proto_id[7]; + + adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC; + adv_proto_id[1] = 5; + WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA); + adv_proto_id[5] = DPP_OUI_TYPE; + adv_proto_id[6] = 0x01; + + if (gas_server_register(wpa_s->gas_server, adv_proto_id, + 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(); + return wpa_s->dpp ? 0 : -1; +} + + +void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_TESTING_OPTIONS + os_free(wpa_s->dpp_config_obj_override); + wpa_s->dpp_config_obj_override = NULL; + os_free(wpa_s->dpp_discovery_override); + wpa_s->dpp_discovery_override = NULL; + os_free(wpa_s->dpp_groups_override); + wpa_s->dpp_groups_override = NULL; + wpa_s->dpp_ignore_netaccesskey_mismatch = 0; +#endif /* CONFIG_TESTING_OPTIONS */ + if (!wpa_s->dpp) + return; + dpp_global_clear(wpa_s->dpp); + eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); + dpp_pfs_free(wpa_s->dpp_pfs); + wpa_s->dpp_pfs = NULL; +#endif /* CONFIG_DPP2 */ + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + wpas_dpp_stop(wpa_s); + wpas_dpp_pkex_remove(wpa_s, "*"); + os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN); + os_free(wpa_s->dpp_configurator_params); + wpa_s->dpp_configurator_params = NULL; +} diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.h b/contrib/wpa/wpa_supplicant/dpp_supplicant.h new file mode 100644 index 000000000000..ecb7a7d684fa --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.h @@ -0,0 +1,29 @@ +/* + * wpa_supplicant - DPP + * Copyright (c) 2017, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DPP_SUPPLICANT_H +#define DPP_SUPPLICANT_H + +int wpas_dpp_qr_code(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); +void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, + unsigned int freq); +void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *buf, size_t len, unsigned int freq); +int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id); +void wpas_dpp_stop(struct wpa_supplicant *wpa_s); +int wpas_dpp_init(struct wpa_supplicant *wpa_s); +void wpas_dpp_deinit(struct wpa_supplicant *wpa_s); +int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_bss *bss); + +#endif /* DPP_SUPPLICANT_H */ diff --git a/contrib/wpa/wpa_supplicant/driver_i.h b/contrib/wpa/wpa_supplicant/driver_i.h index 220b7ba3ddca..4a9f472e84ee 100644 --- a/contrib/wpa/wpa_supplicant/driver_i.h +++ b/contrib/wpa/wpa_supplicant/driver_i.h @@ -189,20 +189,19 @@ static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s, } static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s, - const u8 *bssid, const u8 *pmkid) + struct wpa_pmkid_params *params) { if (wpa_s->driver->add_pmkid) { - return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid); + return wpa_s->driver->add_pmkid(wpa_s->drv_priv, params); } return -1; } static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s, - const u8 *bssid, const u8 *pmkid) + struct wpa_pmkid_params *params) { if (wpa_s->driver->remove_pmkid) { - return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid, - pmkid); + return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, params); } return -1; } @@ -276,11 +275,12 @@ static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s, static inline struct hostapd_hw_modes * wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes, - u16 *flags) + u16 *flags, u8 *dfs_domain) { if (wpa_s->driver->get_hw_feature_data) return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv, - num_modes, flags); + num_modes, flags, + dfs_domain); return NULL; } @@ -492,6 +492,14 @@ static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, return -1; } +static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s, + struct wpa_channel_info *ci) +{ + if (wpa_s->driver->channel_info) + return wpa_s->driver->channel_info(wpa_s->drv_priv, ci); + return -1; +} + static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s, struct hostap_sta_driver_data *sta) { @@ -689,6 +697,14 @@ static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed, return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid); } +static inline int wpa_drv_disable_fils(struct wpa_supplicant *wpa_s, + int disable) +{ + if (!wpa_s->driver->disable_fils) + return -1; + return wpa_s->driver->disable_fils(wpa_s->drv_priv, disable); +} + static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s, const u8 *addr) { @@ -715,6 +731,14 @@ static inline int wpa_drv_macsec_deinit(struct wpa_supplicant *wpa_s) return wpa_s->driver->macsec_deinit(wpa_s->drv_priv); } +static inline int wpa_drv_macsec_get_capability(struct wpa_supplicant *wpa_s, + enum macsec_cap *cap) +{ + if (!wpa_s->driver->macsec_get_capability) + return -1; + return wpa_s->driver->macsec_get_capability(wpa_s->drv_priv, cap); +} + static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s, Boolean enabled) { @@ -723,6 +747,14 @@ static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s, return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled); } +static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s, + Boolean enabled) +{ + if (!wpa_s->driver->enable_encrypt) + return -1; + return wpa_s->driver->enable_encrypt(wpa_s->drv_priv, enabled); +} + static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s, Boolean enabled, u32 window) { @@ -749,145 +781,135 @@ static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s, } static inline int wpa_drv_get_receive_lowest_pn(struct wpa_supplicant *wpa_s, - u32 channel, u8 an, - u32 *lowest_pn) + struct receive_sa *sa) { if (!wpa_s->driver->get_receive_lowest_pn) return -1; - return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, channel, - an, lowest_pn); + return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, sa); } static inline int wpa_drv_get_transmit_next_pn(struct wpa_supplicant *wpa_s, - u32 channel, u8 an, - u32 *next_pn) + struct transmit_sa *sa) { if (!wpa_s->driver->get_transmit_next_pn) return -1; - return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, channel, - an, next_pn); + return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, sa); } static inline int wpa_drv_set_transmit_next_pn(struct wpa_supplicant *wpa_s, - u32 channel, u8 an, - u32 next_pn) + struct transmit_sa *sa) { if (!wpa_s->driver->set_transmit_next_pn) return -1; - return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, channel, - an, next_pn); + return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, sa); } -static inline int wpa_drv_get_available_receive_sc(struct wpa_supplicant *wpa_s, - u32 *channel) +static inline int wpa_drv_set_receive_lowest_pn(struct wpa_supplicant *wpa_s, + struct receive_sa *sa) { - if (!wpa_s->driver->get_available_receive_sc) + if (!wpa_s->driver->set_receive_lowest_pn) return -1; - return wpa_s->driver->get_available_receive_sc(wpa_s->drv_priv, - channel); + return wpa_s->driver->set_receive_lowest_pn(wpa_s->drv_priv, sa); } static inline int -wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, u32 channel, - const u8 *sci_addr, u16 sci_port, +wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, struct receive_sc *sc, unsigned int conf_offset, int validation) { if (!wpa_s->driver->create_receive_sc) return -1; - return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, channel, - sci_addr, sci_port, conf_offset, - validation); + return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, sc, + conf_offset, validation); } static inline int wpa_drv_delete_receive_sc(struct wpa_supplicant *wpa_s, - u32 channel) + struct receive_sc *sc) { if (!wpa_s->driver->delete_receive_sc) return -1; - return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, channel); + return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, sc); } static inline int wpa_drv_create_receive_sa(struct wpa_supplicant *wpa_s, - u32 channel, u8 an, - u32 lowest_pn, const u8 *sak) + struct receive_sa *sa) { if (!wpa_s->driver->create_receive_sa) return -1; - return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, channel, an, - lowest_pn, sak); + return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, sa); } -static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s, - u32 channel, u8 an) +static inline int wpa_drv_delete_receive_sa(struct wpa_supplicant *wpa_s, + struct receive_sa *sa) { - if (!wpa_s->driver->enable_receive_sa) + if (!wpa_s->driver->delete_receive_sa) return -1; - return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, channel, an); + return wpa_s->driver->delete_receive_sa(wpa_s->drv_priv, sa); } -static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s, - u32 channel, u8 an) +static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s, + struct receive_sa *sa) { - if (!wpa_s->driver->disable_receive_sa) + if (!wpa_s->driver->enable_receive_sa) return -1; - return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, channel, an); + return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, sa); } -static inline int -wpa_drv_get_available_transmit_sc(struct wpa_supplicant *wpa_s, u32 *channel) +static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s, + struct receive_sa *sa) { - if (!wpa_s->driver->get_available_transmit_sc) + if (!wpa_s->driver->disable_receive_sa) return -1; - return wpa_s->driver->get_available_transmit_sc(wpa_s->drv_priv, - channel); + return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, sa); } static inline int -wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, u32 channel, - const u8 *sci_addr, u16 sci_port, +wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, struct transmit_sc *sc, unsigned int conf_offset) { if (!wpa_s->driver->create_transmit_sc) return -1; - return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, channel, - sci_addr, sci_port, + return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, sc, conf_offset); } static inline int wpa_drv_delete_transmit_sc(struct wpa_supplicant *wpa_s, - u32 channel) + struct transmit_sc *sc) { if (!wpa_s->driver->delete_transmit_sc) return -1; - return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, channel); + return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, sc); } static inline int wpa_drv_create_transmit_sa(struct wpa_supplicant *wpa_s, - u32 channel, u8 an, - u32 next_pn, - Boolean confidentiality, - const u8 *sak) + struct transmit_sa *sa) { if (!wpa_s->driver->create_transmit_sa) return -1; - return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, channel, an, - next_pn, confidentiality, sak); + return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, sa); +} + +static inline int wpa_drv_delete_transmit_sa(struct wpa_supplicant *wpa_s, + struct transmit_sa *sa) +{ + if (!wpa_s->driver->delete_transmit_sa) + return -1; + return wpa_s->driver->delete_transmit_sa(wpa_s->drv_priv, sa); } static inline int wpa_drv_enable_transmit_sa(struct wpa_supplicant *wpa_s, - u32 channel, u8 an) + struct transmit_sa *sa) { if (!wpa_s->driver->enable_transmit_sa) return -1; - return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, channel, an); + return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, sa); } static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s, - u32 channel, u8 an) + struct transmit_sa *sa) { if (!wpa_s->driver->disable_transmit_sa) return -1; - return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, channel, an); + return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, sa); } #endif /* CONFIG_MACSEC */ @@ -904,6 +926,11 @@ static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s, unsigned int *num, unsigned int *freq_list) { +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->get_pref_freq_list_override) + return wpas_ctrl_iface_get_pref_freq_list_override( + wpa_s, if_type, num, freq_list); +#endif /* CONFIG_TESTING_OPTIONS */ if (!wpa_s->driver->get_pref_freq_list) return -1; return wpa_s->driver->get_pref_freq_list(wpa_s->drv_priv, if_type, @@ -918,11 +945,12 @@ static inline int wpa_drv_set_prob_oper_freq(struct wpa_supplicant *wpa_s, return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq); } -static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s) +static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s, + u64 scan_cookie) { if (!wpa_s->driver->abort_scan) return -1; - return wpa_s->driver->abort_scan(wpa_s->drv_priv); + return wpa_s->driver->abort_scan(wpa_s->drv_priv, scan_cookie); } static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s, @@ -976,4 +1004,70 @@ static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s, return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len); } +static inline int wpa_drv_set_tdls_mode(struct wpa_supplicant *wpa_s, + int tdls_external_control) +{ + if (!wpa_s->driver->set_tdls_mode) + return -1; + return wpa_s->driver->set_tdls_mode(wpa_s->drv_priv, + tdls_external_control); +} + +static inline struct wpa_bss_candidate_info * +wpa_drv_get_bss_trans_status(struct wpa_supplicant *wpa_s, + struct wpa_bss_trans_info *params) +{ + if (!wpa_s->driver->get_bss_transition_status) + return NULL; + return wpa_s->driver->get_bss_transition_status(wpa_s->drv_priv, + params); +} + +static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s, + int val) +{ + if (!wpa_s->driver->ignore_assoc_disallow) + return -1; + return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val); +} + +static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s, + unsigned int num_bssid, + const u8 *bssids) +{ + if (!wpa_s->driver->set_bssid_blacklist) + return -1; + return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid, + bssids); +} + +static inline int wpa_drv_update_connect_params( + struct wpa_supplicant *wpa_s, + struct wpa_driver_associate_params *params, + enum wpa_drv_update_connect_params_mask mask) +{ + if (!wpa_s->driver->update_connect_params) + return -1; + return wpa_s->driver->update_connect_params(wpa_s->drv_priv, params, + mask); +} + +static inline int +wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s, + struct external_auth *params) +{ + if (!wpa_s->driver->send_external_auth_status) + return -1; + return wpa_s->driver->send_external_auth_status(wpa_s->drv_priv, + params); +} + +static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val) +{ + if (!wpa_s->driver->set_4addr_mode) + return -1; + return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv, + wpa_s->bridge_ifname, val); +} + #endif /* DRIVER_I_H */ diff --git a/contrib/wpa/wpa_supplicant/eapol_test.c b/contrib/wpa/wpa_supplicant/eapol_test.c index 6548bd17b11f..3fd4ce61a1c2 100644 --- a/contrib/wpa/wpa_supplicant/eapol_test.c +++ b/contrib/wpa/wpa_supplicant/eapol_test.c @@ -711,7 +711,8 @@ static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx) eap = (struct eap_hdr *) (hdr + 1); eap->code = EAP_CODE_REQUEST; - eap->identifier = 0; + if (os_get_random((u8 *) &eap->identifier, sizeof(eap->identifier)) < 0) + eap->identifier = os_random() & 0xff; eap->length = htons(5); pos = (u8 *) (eap + 1); *pos = EAP_TYPE_IDENTITY; diff --git a/contrib/wpa/wpa_supplicant/eapol_test.py b/contrib/wpa/wpa_supplicant/eapol_test.py index 80e7dfcf531d..734428d29e66 100755 --- a/contrib/wpa/wpa_supplicant/eapol_test.py +++ b/contrib/wpa/wpa_supplicant/eapol_test.py @@ -136,7 +136,7 @@ def main(): results = res[i].get(False) except: results = "N/A" - print "%d: %s" % (i, results) + print("%d: %s" % (i, results)) if __name__ == "__main__": main() diff --git a/contrib/wpa/wpa_supplicant/events.c b/contrib/wpa/wpa_supplicant/events.c index abe3b476773d..f6ec111b77b6 100644 --- a/contrib/wpa/wpa_supplicant/events.c +++ b/contrib/wpa/wpa_supplicant/events.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Driver event processing - * Copyright (c) 2003-2015, 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. @@ -28,6 +28,8 @@ #include "notify.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/gas_server.h" +#include "common/dpp.h" #include "crypto/random.h" #include "blacklist.h" #include "wpas_glue.h" @@ -46,6 +48,10 @@ #include "mesh.h" #include "mesh_mpm.h" #include "wmm_ac.h" +#include "dpp_supplicant.h" + + +#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5 #ifndef CONFIG_NO_SCAN_PROCESSING @@ -54,8 +60,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_SCAN_PROCESSING */ -static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid) +int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct os_reltime now; @@ -289,6 +294,13 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) return; + if (os_reltime_initialized(&wpa_s->session_start)) { + os_reltime_age(&wpa_s->session_start, &wpa_s->session_length); + wpa_s->session_start.sec = 0; + wpa_s->session_start.usec = 0; + wpas_notify_session_length(wpa_s); + } + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); bssid_changed = !is_zero_ether_addr(wpa_s->bssid); os_memset(wpa_s->bssid, 0, ETH_ALEN); @@ -302,7 +314,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) 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)) + 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->ap_ies_from_associnfo = 0; wpa_s->current_ssid = NULL; @@ -311,6 +325,16 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpas_rrm_reset(wpa_s); wpa_s->wnmsleep_used = 0; + wnm_clear_coloc_intf_reporting(wpa_s); + +#ifdef CONFIG_TESTING_OPTIONS + wpa_s->last_tk_alg = WPA_ALG_NONE; + os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk)); +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_s->ieee80211ac = 0; + + if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0) + wpa_s->enabled_4addr_mode = 0; } @@ -327,7 +351,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) for (i = 0; i < ie.num_pmkid; i++) { pmksa_set = pmksa_cache_set_current(wpa_s->wpa, ie.pmkid + i * PMKID_LEN, - NULL, NULL, 0); + NULL, NULL, 0, NULL, 0); if (pmksa_set == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol); break; @@ -479,6 +503,11 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss, return 1; #endif /* CONFIG_WPS */ +#ifdef CONFIG_OWE + if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only) + return 1; +#endif /* CONFIG_OWE */ + if (has_wep_key(ssid)) privacy = 1; @@ -503,7 +532,7 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss, static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, - struct wpa_bss *bss) + struct wpa_bss *bss, int debug_print) { struct wpa_ie_data ie; int proto_match = 0; @@ -522,44 +551,63 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)); rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); - while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) { + while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) { proto_match++; if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse " - "failed"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - parse failed"); break; } + if (!ie.has_pairwise) + ie.pairwise_cipher = wpa_default_rsn_cipher(bss->freq); + if (!ie.has_group) + ie.group_cipher = wpa_default_rsn_cipher(bss->freq); if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) { - wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN " - "in RSN IE"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " selected based on TSN in RSN IE"); return 1; } - if (!(ie.proto & ssid->proto)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto " - "mismatch"); + if (!(ie.proto & ssid->proto) && + !(ssid->proto & WPA_PROTO_OSEN)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - proto mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK " - "cipher mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - PTK cipher mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK " - "cipher mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - GTK cipher mismatch"); + break; + } + + if (ssid->group_mgmt_cipher && + !(ie.mgmt_group_cipher & ssid->group_mgmt_cipher)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - group mgmt cipher mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt " - "mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - key mgmt mismatch"); break; } @@ -567,16 +615,18 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt " - "frame protection"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " 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) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip RSN IE - no mgmt frame protection enabled but AP requires it"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - no mgmt frame protection enabled but AP requires it"); break; } #ifdef CONFIG_MBO @@ -584,20 +634,25 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) && wpas_get_ssid_pmf(wpa_s, ssid) != NO_MGMT_FRAME_PROTECTION) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip RSN IE - no mgmt frame protection enabled on MBO AP"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - no mgmt frame protection enabled on MBO AP"); break; } #endif /* CONFIG_MBO */ - wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " selected based on RSN IE"); return 1; } #ifdef CONFIG_IEEE80211W - if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - MFP Required but network not MFP Capable"); + if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED && + (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - MFP Required but network not MFP Capable"); return 0; } #endif /* CONFIG_IEEE80211W */ @@ -607,72 +662,110 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, proto_match++; if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse " - "failed"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip WPA IE - parse failed"); break; } if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) { - wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN " - "in WPA IE"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " selected based on TSN in WPA IE"); return 1; } if (!(ie.proto & ssid->proto)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto " - "mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip WPA IE - proto mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK " - "cipher mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip WPA IE - PTK cipher mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK " - "cipher mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip WPA IE - GTK cipher mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt " - "mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip WPA IE - key mgmt mismatch"); break; } - wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " selected based on WPA IE"); return 1; } if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie && !rsn_ie) { - wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " allow for non-WPA IEEE 802.1X"); return 1; } +#ifdef CONFIG_OWE + if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only && + !wpa_ie && !rsn_ie) { + if (wpa_s->owe_transition_select && + wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) && + ssid->owe_transition_bss_select_count + 1 <= + MAX_OWE_TRANSITION_BSS_SELECT_COUNT) { + ssid->owe_transition_bss_select_count++; + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip OWE transition BSS (selection count %d does not exceed %d)", + ssid->owe_transition_bss_select_count, + MAX_OWE_TRANSITION_BSS_SELECT_COUNT); + wpa_s->owe_transition_search = 1; + return 0; + } + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " allow in OWE transition mode"); + return 1; + } +#endif /* CONFIG_OWE */ + if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - no WPA/RSN proto match"); return 0; } if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) { - wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN"); return 1; } if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) { - wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2"); return 1; } - wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with " - "WPA/WPA2"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " reject due to mismatch with WPA/WPA2"); return 0; } @@ -692,7 +785,8 @@ static int freq_allowed(int *freqs, int freq) } -static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +static int rate_match(struct wpa_supplicant *wpa_s, 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 }; @@ -749,9 +843,9 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) if (flagged && ((rate_ie[j] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)) { if (!ht_supported(mode)) { - wpa_dbg(wpa_s, MSG_DEBUG, - " hardware does not support " - "HT PHY"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " hardware does not support HT PHY"); return 0; } continue; @@ -761,9 +855,9 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) if (flagged && ((rate_ie[j] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) { if (!vht_supported(mode)) { - wpa_dbg(wpa_s, MSG_DEBUG, - " hardware does not support " - "VHT PHY"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " hardware does not support VHT PHY"); return 0; } continue; @@ -783,10 +877,11 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) * order to join a BSS all required rates * have to be supported by the hardware. */ - wpa_dbg(wpa_s, MSG_DEBUG, - " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)", - r / 10, r % 10, - bss->freq, mode->mode, mode->num_rates); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)", + r / 10, r % 10, + bss->freq, mode->mode, mode->num_rates); return 0; } } @@ -839,39 +934,124 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num) } +static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const u8 **ret_ssid, size_t *ret_ssid_len) +{ +#ifdef CONFIG_OWE + const u8 *owe, *pos, *end, *bssid; + u8 ssid_len; + struct wpa_bss *open_bss; + + owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); + if (!owe || !wpa_bss_get_ie(bss, WLAN_EID_RSN)) + return; + + pos = owe + 6; + end = owe + 2 + owe[1]; + + if (end - pos < ETH_ALEN + 1) + return; + bssid = pos; + pos += ETH_ALEN; + ssid_len = *pos++; + if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN) + return; + + /* Match the profile SSID against the OWE transition mode SSID on the + * open network. */ + wpa_dbg(wpa_s, MSG_DEBUG, "OWE: transition mode BSSID: " MACSTR + " SSID: %s", MAC2STR(bssid), wpa_ssid_txt(pos, ssid_len)); + *ret_ssid = pos; + *ret_ssid_len = ssid_len; + + if (bss->ssid_len > 0) + return; + + open_bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (!open_bss) + return; + if (ssid_len != open_bss->ssid_len || + os_memcmp(pos, open_bss->ssid, ssid_len) != 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "OWE: transition mode SSID mismatch: %s", + wpa_ssid_txt(open_bss->ssid, open_bss->ssid_len)); + return; + } + + owe = wpa_bss_get_vendor_ie(open_bss, OWE_IE_VENDOR_TYPE); + if (!owe || wpa_bss_get_ie(open_bss, WLAN_EID_RSN)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "OWE: transition mode open BSS unexpected info"); + return; + } + + pos = owe + 6; + end = owe + 2 + owe[1]; + + if (end - pos < ETH_ALEN + 1) + return; + if (os_memcmp(pos, bss->bssid, ETH_ALEN) != 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "OWE: transition mode BSSID mismatch: " MACSTR, + MAC2STR(pos)); + return; + } + pos += ETH_ALEN; + ssid_len = *pos++; + if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN) + return; + wpa_dbg(wpa_s, MSG_DEBUG, "OWE: learned transition mode OWE SSID: %s", + wpa_ssid_txt(pos, ssid_len)); + os_memcpy(bss->ssid, pos, ssid_len); + bss->ssid_len = ssid_len; +#endif /* CONFIG_OWE */ +} + + struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_bss *bss, struct wpa_ssid *group, - int only_first_ssid) + int only_first_ssid, int debug_print) { u8 wpa_ie_len, rsn_ie_len; int wpa; struct wpa_blacklist *e; const u8 *ie; struct wpa_ssid *ssid; - int osen; + int osen, rsn_osen = 0; #ifdef CONFIG_MBO const u8 *assoc_disallow; #endif /* CONFIG_MBO */ + const u8 *match_ssid; + size_t match_ssid_len; + struct wpa_ie_data data; ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); wpa_ie_len = ie ? ie[1] : 0; ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); rsn_ie_len = ie ? ie[1] : 0; + if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 && + (data.key_mgmt & WPA_KEY_MGMT_OSEN)) + rsn_osen = 1; ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); osen = ie != NULL; - wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' " - "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s", - i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len), - wpa_ie_len, rsn_ie_len, bss->caps, bss->level, bss->freq, - wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "", - (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || - wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ? - " p2p" : "", - osen ? " osen=1" : ""); + if (debug_print) { + wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR + " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s", + i, MAC2STR(bss->bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len), + wpa_ie_len, rsn_ie_len, bss->caps, bss->level, + bss->freq, + wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? + " wps" : "", + (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || + wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) + ? " p2p" : "", + osen ? " osen=1" : ""); + } e = wpa_blacklist_get(wpa_s, bss->bssid); if (e) { @@ -888,24 +1068,34 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, limit = 0; } if (e->count > limit) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted " - "(count=%d limit=%d)", e->count, limit); + if (debug_print) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - blacklisted (count=%d limit=%d)", + e->count, limit); + } return NULL; } } - if (bss->ssid_len == 0) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known"); + match_ssid = bss->ssid; + match_ssid_len = bss->ssid_len; + owe_trans_ssid(wpa_s, bss, &match_ssid, &match_ssid_len); + + if (match_ssid_len == 0) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known"); return NULL; } if (disallowed_bssid(wpa_s, bss->bssid)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed"); return NULL; } - if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed"); + if (disallowed_ssid(wpa_s, match_ssid, match_ssid_len)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed"); return NULL; } @@ -916,21 +1106,25 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int res; if (wpas_network_disabled(wpa_s, ssid)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled"); continue; } res = wpas_temp_disabled(wpa_s, ssid); if (res > 0) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled " - "temporarily for %d second(s)", res); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - disabled temporarily for %d second(s)", + res); continue; } #ifdef CONFIG_WPS if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted " - "(WPS)"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - blacklisted (WPS)"); continue; } @@ -954,15 +1148,19 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, check_ssid = 0; if (check_ssid && - (bss->ssid_len != ssid->ssid_len || - os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch"); + (match_ssid_len != ssid->ssid_len || + os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - SSID mismatch"); continue; } if (ssid->bssid_set && os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - BSSID mismatch"); continue; } @@ -970,8 +1168,9 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, if (ssid->num_bssid_blacklist && addr_in_list(bss->bssid, ssid->bssid_blacklist, ssid->num_bssid_blacklist)) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - BSSID blacklisted"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - BSSID blacklisted"); continue; } @@ -979,79 +1178,108 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, if (ssid->num_bssid_whitelist && !addr_in_list(bss->bssid, ssid->bssid_whitelist, ssid->num_bssid_whitelist)) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - BSSID not in whitelist"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - BSSID not in whitelist"); continue; } - if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) + if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, + debug_print)) continue; if (!osen && !wpa && !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && + !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-WPA network " - "not allowed"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - non-WPA network not allowed"); continue; } if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - ignore WPA/WPA2 AP for WEP network block"); continue; } - if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-OSEN network " - "not allowed"); + if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && + !rsn_osen) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - non-OSEN network not allowed"); continue; } if (!wpa_supplicant_match_privacy(bss, ssid)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy " - "mismatch"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - privacy mismatch"); continue; } if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) && !bss_is_pbss(bss)) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - not ESS, PBSS, or MBSS"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - not ESS, PBSS, or MBSS"); continue; } if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - PBSS mismatch (ssid %d bss %d)", - ssid->pbss, bss_is_pbss(bss)); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - PBSS mismatch (ssid %d bss %d)", + ssid->pbss, bss_is_pbss(bss)); continue; } if (!freq_allowed(ssid->freq_list, bss->freq)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not " - "allowed"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - frequency not allowed"); continue; } #ifdef CONFIG_MESH if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 && ssid->frequency != bss->freq) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not allowed (mesh)"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - frequency not allowed (mesh)"); continue; } #endif /* CONFIG_MESH */ - if (!rate_match(wpa_s, bss)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do " - "not match"); + if (!rate_match(wpa_s, bss, debug_print)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - rate sets do not match"); continue; } +#ifndef CONFIG_IBSS_RSN + if (ssid->mode == WPAS_MODE_IBSS && + !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | + WPA_KEY_MGMT_WPA_NONE))) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - IBSS RSN not supported in the build"); + continue; + } +#endif /* !CONFIG_IBSS_RSN */ + #ifdef CONFIG_P2P if (ssid->p2p_group && !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) && !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - no P2P IE seen"); continue; } @@ -1061,20 +1289,26 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); if (ie == NULL) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P element"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - no P2P element"); continue; } p2p_ie = wpa_bss_get_vendor_ie_multi( bss, P2P_IE_VENDOR_TYPE); if (p2p_ie == NULL) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - could not fetch P2P element"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - could not fetch P2P element"); continue; } if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 || os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - no matching GO P2P Device Address in P2P element"); + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - no matching GO P2P Device Address in P2P element"); wpabuf_free(p2p_ie); continue; } @@ -1094,8 +1328,9 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, os_reltime_sub(&wpa_s->scan_min_time, &bss->last_update, &diff); - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - scan result not recent enough (%u.%06u seconds too old)", + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - scan result not recent enough (%u.%06u seconds too old)", (unsigned int) diff.sec, (unsigned int) diff.usec); continue; @@ -1108,15 +1343,17 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, assoc_disallow = wpas_mbo_get_bss_attr( bss, MBO_ATTR_ID_ASSOC_DISALLOW); if (assoc_disallow && assoc_disallow[1] >= 1) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - MBO association disallowed (reason %u)", + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - MBO association disallowed (reason %u)", assoc_disallow[2]); continue; } - if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) { - wpa_dbg(wpa_s, MSG_DEBUG, - " skip - MBO retry delay has not passed yet"); + if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - AP temporarily disallowed"); continue; } #ifdef CONFIG_TESTING_OPTIONS @@ -1124,6 +1361,19 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_MBO */ +#ifdef CONFIG_DPP + if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) && + !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) && + (!ssid->dpp_connector || + !ssid->dpp_netaccesskey || + !ssid->dpp_csign)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - no PMKSA entry for DPP"); + continue; + } +#endif /* CONFIG_DPP */ + /* Matching configuration found */ return ssid; } @@ -1141,6 +1391,25 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, { unsigned int i; + if (wpa_s->current_ssid) { + struct wpa_ssid *ssid; + + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan results matching the currently selected network"); + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + struct wpa_bss *bss = wpa_s->last_scan_res[i]; + + ssid = wpa_scan_res_match(wpa_s, i, bss, group, + only_first_ssid, 0); + if (ssid != wpa_s->current_ssid) + continue; + wpa_dbg(wpa_s, MSG_DEBUG, "%u: " MACSTR + " freq=%d level=%d snr=%d est_throughput=%u", + i, MAC2STR(bss->bssid), bss->freq, bss->level, + bss->snr, bss->est_throughput); + } + } + if (only_first_ssid) wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d", group->id); @@ -1150,8 +1419,11 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, for (i = 0; i < wpa_s->last_scan_res_used; i++) { struct wpa_bss *bss = wpa_s->last_scan_res[i]; + + wpa_s->owe_transition_select = 1; *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group, - only_first_ssid); + only_first_ssid, 1); + wpa_s->owe_transition_select = 0; if (!*selected_ssid) continue; wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR @@ -1332,6 +1604,17 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s) { if (wpas_network_disabled(wpa_s, ssid)) continue; +#ifndef CONFIG_IBSS_RSN + if (ssid->mode == WPAS_MODE_IBSS && + !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | + WPA_KEY_MGMT_WPA_NONE))) { + wpa_msg(wpa_s, MSG_INFO, + "IBSS RSN not supported in the build - cannot use the profile for SSID '%s'", + wpa_ssid_txt(ssid->ssid, + ssid->ssid_len)); + continue; + } +#endif /* !CONFIG_IBSS_RSN */ if (ssid->mode == IEEE80211_MODE_IBSS || ssid->mode == IEEE80211_MODE_AP || ssid->mode == IEEE80211_MODE_MESH) @@ -1375,8 +1658,9 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, { struct wpa_bss *current_bss = NULL; #ifndef CONFIG_NO_ROAMING - int min_diff; + int min_diff, diff; int to_5ghz; + int cur_est, sel_est; #endif /* CONFIG_NO_ROAMING */ if (wpa_s->reassociate) @@ -1410,12 +1694,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, #ifndef CONFIG_NO_ROAMING wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation"); wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR - " level=%d snr=%d est_throughput=%u", - MAC2STR(current_bss->bssid), current_bss->level, + " freq=%d level=%d snr=%d est_throughput=%u", + MAC2STR(current_bss->bssid), + current_bss->freq, current_bss->level, current_bss->snr, current_bss->est_throughput); wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR - " level=%d snr=%d est_throughput=%u", - MAC2STR(selected->bssid), selected->level, + " freq=%d level=%d snr=%d est_throughput=%u", + MAC2STR(selected->bssid), selected->freq, selected->level, selected->snr, selected->est_throughput); if (wpa_s->current_ssid->bssid_set && @@ -1441,6 +1726,14 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, return 0; } + if (current_bss->est_throughput > selected->est_throughput + 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) @@ -1453,20 +1746,42 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, 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 (to_5ghz) { + int reduce = 2; + /* Make it easier to move to 5 GHz band */ - if (min_diff > 2) - min_diff -= 2; + 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 (min_diff > reduce) + min_diff -= reduce; else min_diff = 0; } - if (abs(current_bss->level - selected->level) < min_diff) { - wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference " - "in signal level"); + diff = abs(current_bss->level - selected->level); + if (diff < min_diff) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Skip roam - too small difference in signal level (%d < %d)", + diff, min_diff); return 0; } + wpa_dbg(wpa_s, MSG_DEBUG, + "Allow reassociation due to difference in signal level (%d >= %d)", + diff, min_diff); return 1; #else /* CONFIG_NO_ROAMING */ return 0; @@ -1474,11 +1789,18 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, } -/* Return != 0 if no scan results could be fetched or if scan results should not - * be shared with other virtual interfaces. */ +/* + * Return a negative value if no scan results could be fetched or if scan + * results should not be shared with other virtual interfaces. + * Return 0 if scan results were fetched and may be shared with other + * interfaces. + * Return 1 if scan results may be shared with other virtual interfaces but may + * not trigger any operations. + * Return 2 if the interface was removed and cannot be used. + */ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, union wpa_event_data *data, - int own_request) + int own_request, int update_only) { struct wpa_scan_results *scan_res = NULL; int ret = 0; @@ -1528,6 +1850,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_NO_RANDOM_POOL */ + if (update_only) { + ret = 1; + goto scan_work_done; + } + if (own_request && wpa_s->scan_res_handler && !(data && data->scan_info.external_scan)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, @@ -1536,7 +1863,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, scan_res_handler = wpa_s->scan_res_handler; wpa_s->scan_res_handler = NULL; scan_res_handler(wpa_s, scan_res); - ret = -2; + ret = 1; goto scan_work_done; } @@ -1577,6 +1904,10 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (sme_proc_obss_scan(wpa_s) > 0) goto scan_work_done; + if (own_request && data && + wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0) + goto scan_work_done; + if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) goto scan_work_done; @@ -1639,6 +1970,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, if (wpa_s->p2p_mgmt) return 0; /* no normal connection on p2p_mgmt interface */ + wpa_s->owe_transition_search = 0; selected = wpa_supplicant_pick_network(wpa_s, &ssid); #ifdef CONFIG_MESH @@ -1672,8 +2004,9 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, if (new_scan) wpa_supplicant_rsn_preauth_scan_results(wpa_s); /* - * Do not notify other virtual radios of scan results since we do not - * want them to start other associations at the same time. + * Do not allow other virtual radios to trigger operations based + * on these scan results since we do not want them to start + * other associations at the same time. */ return 1; } else { @@ -1739,6 +2072,17 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; } #endif /* CONFIG_WPS */ +#ifdef CONFIG_OWE + if (wpa_s->owe_transition_search) { + wpa_dbg(wpa_s, MSG_DEBUG, + "OWE: Use shorter wait during transition mode search"); + timeout_sec = 0; + timeout_usec = 500000; + wpa_supplicant_req_new_scan(wpa_s, timeout_sec, + timeout_usec); + return 0; + } +#endif /* CONFIG_OWE */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); @@ -1757,7 +2101,7 @@ static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, struct wpa_supplicant *ifs; int res; - res = _wpa_supplicant_event_scan_results(wpa_s, data, 1); + res = _wpa_supplicant_event_scan_results(wpa_s, data, 1, 0); if (res == 2) { /* * Interface may have been removed, so must not dereference @@ -1765,7 +2109,8 @@ static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, */ return 1; } - if (res != 0) { + + if (res < 0) { /* * If no scan results could be fetched, then no need to * notify those interfaces that did not actually request @@ -1785,7 +2130,10 @@ static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (ifs != wpa_s) { wpa_printf(MSG_DEBUG, "%s: Updating scan results from " "sibling", ifs->ifname); - _wpa_supplicant_event_scan_results(ifs, data, 0); + res = _wpa_supplicant_event_scan_results(ifs, data, 0, + res > 0); + if (res < 0) + return 0; } } @@ -1802,6 +2150,8 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s) #else /* CONFIG_NO_SCAN_PROCESSING */ struct os_reltime now; + wpa_s->ignore_post_flush_scan_res = 0; + if (wpa_s->last_scan_res_used == 0) return -1; @@ -1932,6 +2282,57 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t ies_len) +{ + struct ieee802_11_elems elems; + const u8 *map_sub_elem, *pos; + size_t len; + + if (!wpa_s->current_ssid || + !wpa_s->current_ssid->multi_ap_backhaul_sta || + !ies || + ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) + return; + + if (!elems.multi_ap || elems.multi_ap_len < 7) { + wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol"); + goto fail; + } + + pos = elems.multi_ap + 4; + len = elems.multi_ap_len - 4; + + map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE); + if (!map_sub_elem || map_sub_elem[1] < 1) { + wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type"); + goto fail; + } + + if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) { + if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) && + wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) { + wpa_printf(MSG_INFO, + "WPS active, accepting fronthaul-only BSS"); + /* Don't set 4addr mode in this case, so just return */ + return; + } + wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS"); + goto fail; + } + + if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) { + wpa_printf(MSG_ERROR, "Failed to set 4addr mode"); + goto fail; + } + wpa_s->enabled_4addr_mode = 1; + return; + +fail: + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); +} + + #ifdef CONFIG_FST static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s, const u8 *ie, size_t ie_len) @@ -1981,9 +2382,9 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, { int l, len, found = 0, wpa_found, rsn_found; const u8 *p; -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE) u8 bssid[ETH_ALEN]; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R || CONFIG_OWE */ wpa_dbg(wpa_s, MSG_DEBUG, "Association info event"); if (data->assoc_info.req_ies) @@ -2004,6 +2405,13 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_INTERWORKING */ + if (wpa_s->hw_capab == CAPAB_VHT && + get_ie(data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP)) + wpa_s->ieee80211ac = 1; + + multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); } if (data->assoc_info.beacon_ies) wpa_hexdump(MSG_DEBUG, "beacon_ies", @@ -2013,6 +2421,26 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz", data->assoc_info.freq); + wpa_s->connection_set = 0; + if (data->assoc_info.req_ies && data->assoc_info.resp_ies) { + struct ieee802_11_elems req_elems, resp_elems; + + if (ieee802_11_parse_elems(data->assoc_info.req_ies, + data->assoc_info.req_ies_len, + &req_elems, 0) != ParseFailed && + ieee802_11_parse_elems(data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, + &resp_elems, 0) != ParseFailed) { + wpa_s->connection_set = 1; + wpa_s->connection_ht = req_elems.ht_capabilities && + resp_elems.ht_capabilities; + wpa_s->connection_vht = req_elems.vht_capabilities && + resp_elems.vht_capabilities; + wpa_s->connection_he = req_elems.he_capabilities && + resp_elems.he_capabilities; + } + } + p = data->assoc_info.req_ies; l = data->assoc_info.req_ies_len; @@ -2041,6 +2469,58 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, if (!found && data->assoc_info.req_ies) wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); +#ifdef CONFIG_FILS +#ifdef CONFIG_SME + if ((wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS || + wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) && + (!data->assoc_info.resp_frame || + fils_process_assoc_resp(wpa_s->wpa, + data->assoc_info.resp_frame, + data->assoc_info.resp_frame_len) < 0)) { + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); + return -1; + } +#endif /* CONFIG_SME */ + + /* Additional processing for FILS when SME is in driver */ + if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) + wpa_sm_set_reset_fils_completed(wpa_s->wpa, 1); +#endif /* CONFIG_FILS */ + +#ifdef CONFIG_OWE + if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE && + (wpa_drv_get_bssid(wpa_s, bssid) < 0 || + owe_process_assoc_resp(wpa_s->wpa, bssid, + data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len) < 0)) { + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); + return -1; + } +#endif /* CONFIG_OWE */ + +#ifdef CONFIG_DPP2 + wpa_sm_set_dpp_z(wpa_s->wpa, NULL); + if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) { + struct ieee802_11_elems elems; + + if (ieee802_11_parse_elems(data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, + &elems, 0) == ParseFailed || + !elems.owe_dh) + goto no_pfs; + if (dpp_pfs_process(wpa_s->dpp_pfs, elems.owe_dh, + elems.owe_dh_len) < 0) { + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_UNSPECIFIED); + return -1; + } + + wpa_sm_set_dpp_z(wpa_s->wpa, wpa_s->dpp_pfs->secret); + } +no_pfs: +#endif /* CONFIG_DPP2 */ + #ifdef CONFIG_IEEE80211R #ifdef CONFIG_SME if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) { @@ -2262,6 +2742,13 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, ft_completed = wpa_ft_is_completed(wpa_s->wpa); if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) return; + /* + * FILS authentication can share the same mechanism to mark the + * connection fully authenticated, so set ft_completed also based on + * FILS result. + */ + if (!ft_completed) + ft_completed = wpa_fils_is_completed(wpa_s->wpa); if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID"); @@ -2272,6 +2759,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { + if (os_reltime_initialized(&wpa_s->session_start)) { + os_reltime_age(&wpa_s->session_start, + &wpa_s->session_length); + wpa_s->session_start.sec = 0; + wpa_s->session_start.usec = 0; + wpas_notify_session_length(wpa_s); + } else { + wpas_notify_auth_changed(wpa_s); + os_get_reltime(&wpa_s->session_start); + } wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID=" MACSTR, MAC2STR(bssid)); new_bss = 1; @@ -2331,7 +2828,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, 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) || ft_completed || + 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); /* 802.1X::portControl = Auto */ @@ -2360,8 +2859,17 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, } wpa_supplicant_cancel_scan(wpa_s); - if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && - wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { + if (ft_completed) { + /* + * FT protocol completed - make sure EAPOL state machine ends + * up in authenticated. + */ + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + eapol_sm_notify_portValid(wpa_s->eapol, TRUE); + eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); + } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) && + wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { /* * We are done; the driver will take care of RSN 4-way * handshake. @@ -2370,7 +2878,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); eapol_sm_notify_portValid(wpa_s->eapol, TRUE); eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); - } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && + } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) && wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { /* * The driver will take care of RSN 4-way handshake, so we need @@ -2378,15 +2886,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, * waiting for WPA supplicant. */ eapol_sm_notify_portValid(wpa_s->eapol, TRUE); - } else if (ft_completed) { - /* - * FT protocol completed - make sure EAPOL state machine ends - * up in authenticated. - */ - 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); } wpa_s->last_eapol_matches_bssid = 0; @@ -2395,7 +2894,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, struct os_reltime now, age; os_get_reltime(&now); os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age); - if (age.sec == 0 && age.usec < 100000 && + if (age.sec == 0 && age.usec < 200000 && os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL " @@ -2446,6 +2945,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (wpa_s->reassoc_same_bss) wmm_ac_restore_tspecs(wpa_s); } + +#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 */ } @@ -2622,7 +3131,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, !disallowed_ssid(wpa_s, fast_reconnect->ssid, fast_reconnect->ssid_len) && !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) && - !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) { + !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) { #ifndef CONFIG_NO_SCAN_PROCESSING wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS"); if (wpa_supplicant_connect(wpa_s, fast_reconnect, @@ -2837,18 +3346,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s, } -#ifdef CONFIG_PEERKEY -static void -wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) -{ - if (data == NULL) - return; - wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer); -} -#endif /* CONFIG_PEERKEY */ - - #ifdef CONFIG_TDLS static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s, union wpa_event_data *data) @@ -3207,10 +3704,11 @@ static const char * reg_type_str(enum reg_type type) } -static void wpa_supplicant_update_channel_list( - struct wpa_supplicant *wpa_s, struct channel_list_changed *info) +void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, + struct channel_list_changed *info) { struct wpa_supplicant *ifs; + u8 dfs_domain; /* * To allow backwards compatibility with higher level layers that @@ -3221,10 +3719,13 @@ static void wpa_supplicant_update_channel_list( for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent) ; - wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s", - reg_init_str(info->initiator), reg_type_str(info->type), - info->alpha2[0] ? " alpha2=" : "", - info->alpha2[0] ? info->alpha2 : ""); + if (info) { + wpa_msg(ifs, MSG_INFO, + WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s", + reg_init_str(info->initiator), reg_type_str(info->type), + info->alpha2[0] ? " alpha2=" : "", + info->alpha2[0] ? info->alpha2 : ""); + } if (wpa_s->drv_priv == NULL) return; /* Ignore event during drv initialization */ @@ -3235,7 +3736,7 @@ static void wpa_supplicant_update_channel_list( ifs->ifname); free_hw_features(ifs); ifs->hw.modes = wpa_drv_get_hw_feature_data( - ifs, &ifs->hw.num_modes, &ifs->hw.flags); + ifs, &ifs->hw.num_modes, &ifs->hw.flags, &dfs_domain); /* Restart PNO/sched_scan with updated channel list */ if (ifs->pno) { @@ -3310,6 +3811,15 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, return; #endif /* CONFIG_GAS */ +#ifdef CONFIG_GAS_SERVER + if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC || + mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) && + gas_server_rx(wpa_s->gas_server, mgmt->da, mgmt->sa, mgmt->bssid, + mgmt->u.action.category, + payload, plen, freq) == 0) + return; +#endif /* CONFIG_GAS_SERVER */ + #ifdef CONFIG_TDLS if (category == WLAN_ACTION_PUBLIC && plen >= 4 && payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) { @@ -3338,6 +3848,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, if (category == WLAN_ACTION_RADIO_MEASUREMENT && payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) { wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa, + mgmt->da, payload + 1, plen - 1); return; @@ -3364,6 +3875,18 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_FST */ +#ifdef CONFIG_DPP + if (category == WLAN_ACTION_PUBLIC && plen >= 5 && + payload[0] == WLAN_PA_VENDOR_SPECIFIC && + WPA_GET_BE24(&payload[1]) == OUI_WFA && + payload[4] == DPP_OUI_TYPE) { + payload++; + plen--; + wpas_dpp_rx_action(wpa_s, mgmt->sa, payload, plen, freq); + return; + } +#endif /* CONFIG_DPP */ + wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, category, payload, plen, freq); if (wpa_s->ifmsh) @@ -3404,23 +3927,252 @@ static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s, } -static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) +static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s) { - wpa_dbg(wpa_s, MSG_DEBUG, - "Connection authorized by device, previous state %d", - wpa_s->wpa_state); if (wpa_s->wpa_state == WPA_ASSOCIATED) { wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); eapol_sm_notify_portValid(wpa_s->eapol, TRUE); eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); } +} + + +static unsigned int wpas_event_cac_ms(const struct wpa_supplicant *wpa_s, + int freq) +{ + size_t i; + int j; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + const struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; + + for (j = 0; j < mode->num_channels; j++) { + const struct hostapd_channel_data *chan; + + chan = &mode->channels[j]; + if (chan->freq == freq) + return chan->dfs_cac_ms; + } + } + + return 0; +} + + +static void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) +{ +#if defined(NEED_AP_MLME) && defined(CONFIG_AP) + if (wpa_s->ap_iface || wpa_s->ifmsh) { + wpas_ap_event_dfs_cac_started(wpa_s, radar); + } else +#endif /* NEED_AP_MLME && CONFIG_AP */ + { + unsigned int cac_time = wpas_event_cac_ms(wpa_s, radar->freq); + + cac_time /= 1000; /* convert from ms to sec */ + if (!cac_time) + cac_time = 10 * 60; /* max timeout: 10 minutes */ + + /* Restart auth timeout: CAC time added to initial timeout */ + wpas_auth_timeout_restart(wpa_s, cac_time); + } +} + + +static void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) +{ +#if defined(NEED_AP_MLME) && defined(CONFIG_AP) + if (wpa_s->ap_iface || wpa_s->ifmsh) { + wpas_ap_event_dfs_cac_finished(wpa_s, radar); + } else +#endif /* NEED_AP_MLME && CONFIG_AP */ + { + /* Restart auth timeout with original value after CAC is + * finished */ + wpas_auth_timeout_restart(wpa_s, 0); + } +} + + +static void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s, + struct dfs_event *radar) +{ +#if defined(NEED_AP_MLME) && defined(CONFIG_AP) + if (wpa_s->ap_iface || wpa_s->ifmsh) { + wpas_ap_event_dfs_cac_aborted(wpa_s, radar); + } else +#endif /* NEED_AP_MLME && CONFIG_AP */ + { + /* Restart auth timeout with original value after CAC is + * aborted */ + wpas_auth_timeout_restart(wpa_s, 0); + } +} + + +static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + wpa_dbg(wpa_s, MSG_DEBUG, + "Connection authorized by device, previous state %d", + wpa_s->wpa_state); + + wpa_supplicant_event_port_authorized(wpa_s); + wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr); wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck, data->assoc_info.ptk_kck_len, data->assoc_info.ptk_kek, data->assoc_info.ptk_kek_len); +#ifdef CONFIG_FILS + if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) { + struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid); + const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss); + + /* Update ERP next sequence number */ + eapol_sm_update_erp_next_seq_num( + wpa_s->eapol, data->assoc_info.fils_erp_next_seq_num); + + if (data->assoc_info.fils_pmk && data->assoc_info.fils_pmkid) { + /* Add the new PMK and PMKID to the PMKSA cache */ + wpa_sm_pmksa_cache_add(wpa_s->wpa, + data->assoc_info.fils_pmk, + data->assoc_info.fils_pmk_len, + data->assoc_info.fils_pmkid, + wpa_s->bssid, fils_cache_id); + } else if (data->assoc_info.fils_pmkid) { + /* Update the current PMKSA used for this connection */ + pmksa_cache_set_current(wpa_s->wpa, + data->assoc_info.fils_pmkid, + NULL, NULL, 0, NULL, 0); + } + } +#endif /* CONFIG_FILS */ +} + + +static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + const u8 *bssid = data->assoc_reject.bssid; + + if (!bssid || is_zero_ether_addr(bssid)) + bssid = wpa_s->pending_bssid; + + if (data->assoc_reject.bssid) + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT + "bssid=" MACSTR " status_code=%u%s%s%s", + MAC2STR(data->assoc_reject.bssid), + data->assoc_reject.status_code, + data->assoc_reject.timed_out ? " timeout" : "", + data->assoc_reject.timeout_reason ? "=" : "", + data->assoc_reject.timeout_reason ? + data->assoc_reject.timeout_reason : ""); + else + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT + "status_code=%u%s%s%s", + data->assoc_reject.status_code, + data->assoc_reject.timed_out ? " timeout" : "", + data->assoc_reject.timeout_reason ? "=" : "", + data->assoc_reject.timeout_reason ? + data->assoc_reject.timeout_reason : ""); + wpa_s->assoc_status_code = data->assoc_reject.status_code; + wpas_notify_assoc_status_code(wpa_s); + +#ifdef CONFIG_OWE + if (data->assoc_reject.status_code == + WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && + wpa_s->key_mgmt == WPA_KEY_MGMT_OWE && + wpa_s->current_ssid && + wpa_s->current_ssid->owe_group == 0 && + wpa_s->last_owe_group != 21) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + struct wpa_bss *bss = wpa_s->current_bss; + + if (!bss) { + bss = wpa_supplicant_get_new_bss(wpa_s, bssid); + if (!bss) { + wpas_connection_failed(wpa_s, bssid); + wpa_supplicant_mark_disassoc(wpa_s); + return; + } + } + wpa_printf(MSG_DEBUG, "OWE: Try next supported DH group"); + wpas_connect_work_done(wpa_s); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_supplicant_connect(wpa_s, bss, ssid); + return; + } +#endif /* CONFIG_OWE */ + +#ifdef CONFIG_MBO + if (data->assoc_reject.status_code == + WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS && + wpa_s->current_bss && data->assoc_reject.bssid && + data->assoc_reject.resp_ies) { + const u8 *rssi_rej; + + rssi_rej = mbo_get_attr_from_ies( + data->assoc_reject.resp_ies, + data->assoc_reject.resp_ies_len, + OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT); + if (rssi_rej && rssi_rej[1] == 2) { + wpa_printf(MSG_DEBUG, + "OCE: RSSI-based association rejection from " + MACSTR " (Delta RSSI: %u, Retry Delay: %u)", + MAC2STR(data->assoc_reject.bssid), + rssi_rej[2], rssi_rej[3]); + wpa_bss_tmp_disallow(wpa_s, + data->assoc_reject.bssid, + rssi_rej[3], + rssi_rej[2] + + wpa_s->current_bss->level); + } + } +#endif /* CONFIG_MBO */ + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) { + sme_event_assoc_reject(wpa_s, data); + return; + } + + /* Driver-based SME cases */ + +#ifdef CONFIG_SAE + if (wpa_s->current_ssid && + wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt) && + !data->assoc_reject.timed_out) { + wpa_dbg(wpa_s, MSG_DEBUG, "SAE: Drop PMKSA cache entry"); + wpa_sm_aborted_cached(wpa_s->wpa); + wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid); + } +#endif /* CONFIG_SAE */ + +#ifdef CONFIG_DPP + if (wpa_s->current_ssid && + wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP && + !data->assoc_reject.timed_out) { + wpa_dbg(wpa_s, MSG_DEBUG, "DPP: Drop PMKSA cache entry"); + wpa_sm_aborted_cached(wpa_s->wpa); + wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid); + } +#endif /* CONFIG_DPP */ + +#ifdef CONFIG_FILS + /* Update ERP next sequence number */ + if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) { + eapol_sm_update_erp_next_seq_num( + wpa_s->eapol, + data->assoc_reject.fils_erp_next_seq_num); + fils_connection_failure(wpa_s); + } +#endif /* CONFIG_FILS */ + + wpas_connection_failed(wpa_s, bssid); + wpa_supplicant_mark_disassoc(wpa_s); } @@ -3429,6 +4181,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, { struct wpa_supplicant *wpa_s = ctx; int resched; +#ifndef CONFIG_NO_STDOUT_DEBUG + int level = MSG_DEBUG; +#endif /* CONFIG_NO_STDOUT_DEBUG */ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && @@ -3442,9 +4197,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } #ifndef CONFIG_NO_STDOUT_DEBUG -{ - int level = MSG_DEBUG; - if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) { const struct ieee80211_hdr *hdr; u16 fc; @@ -3457,7 +4209,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_dbg(wpa_s, level, "Event %s (%d) received", event_to_string(event), event); -} #endif /* CONFIG_NO_STDOUT_DEBUG */ switch (event) { @@ -3469,6 +4220,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, "FST: MB IEs updated from auth IE"); #endif /* CONFIG_FST */ sme_event_auth(wpa_s, data); + wpa_s->auth_status_code = data->auth.status_code; + wpas_notify_auth_status_code(wpa_s); break; case EVENT_ASSOC: #ifdef CONFIG_TESTING_OPTIONS @@ -3477,9 +4230,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, "EVENT_ASSOC - ignore_auth_resp active!"); break; } + if (wpa_s->testing_resend_assoc) { + wpa_printf(MSG_INFO, + "EVENT_DEAUTH - testing_resend_assoc"); + break; + } #endif /* CONFIG_TESTING_OPTIONS */ wpa_supplicant_event_assoc(wpa_s, data); - if (data && data->assoc_info.authorized) + wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS; + if (data && + (data->assoc_info.authorized || + (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + wpa_fils_is_completed(wpa_s->wpa)))) wpa_supplicant_event_assoc_auth(wpa_s, data); if (data) { wpa_msg(wpa_s, MSG_INFO, @@ -3498,6 +4260,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, "EVENT_DEAUTH - ignore_auth_resp active!"); break; } + if (wpa_s->testing_resend_assoc) { + wpa_printf(MSG_INFO, + "EVENT_DEAUTH - testing_resend_assoc"); + break; + } #endif /* CONFIG_TESTING_OPTIONS */ wpas_event_deauth(wpa_s, data ? &data->deauth_info : NULL); @@ -3570,11 +4337,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_PMKID_CANDIDATE: wpa_supplicant_event_pmkid_candidate(wpa_s, data); break; -#ifdef CONFIG_PEERKEY - case EVENT_STKSTART: - wpa_supplicant_event_stkstart(wpa_s, data); - break; -#endif /* CONFIG_PEERKEY */ #ifdef CONFIG_TDLS case EVENT_TDLS: wpa_supplicant_event_tdls(wpa_s, data); @@ -3596,28 +4358,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #endif /* CONFIG_IBSS_RSN */ case EVENT_ASSOC_REJECT: - if (data->assoc_reject.bssid) - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "bssid=" MACSTR " status_code=%u%s", - MAC2STR(data->assoc_reject.bssid), - data->assoc_reject.status_code, - data->assoc_reject.timed_out ? " timeout" : ""); - else - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "status_code=%u%s", - data->assoc_reject.status_code, - data->assoc_reject.timed_out ? " timeout" : ""); - wpa_s->assoc_status_code = data->assoc_reject.status_code; - wpas_notify_assoc_status_code(wpa_s); - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) - sme_event_assoc_reject(wpa_s, data); - else { - const u8 *bssid = data->assoc_reject.bssid; - if (bssid == NULL || is_zero_ether_addr(bssid)) - bssid = wpa_s->pending_bssid; - wpas_connection_failed(wpa_s, bssid); - wpa_supplicant_mark_disassoc(wpa_s); - } + wpas_event_assoc_reject(wpa_s, data); break; case EVENT_AUTH_TIMED_OUT: /* It is possible to get this event from earlier connection */ @@ -3719,6 +4460,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr, data->rx_from_unknown.wds); break; +#endif /* CONFIG_AP */ case EVENT_CH_SWITCH: if (!data || !wpa_s->current_ssid) break; @@ -3735,8 +4477,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s->assoc_freq = data->ch_switch.freq; wpa_s->current_ssid->frequency = data->ch_switch.freq; +#ifdef CONFIG_AP if (wpa_s->current_ssid->mode == WPAS_MODE_AP || wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO || + wpa_s->current_ssid->mode == WPAS_MODE_MESH || wpa_s->current_ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) { wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, @@ -3746,14 +4490,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.cf1, data->ch_switch.cf2); } +#endif /* CONFIG_AP */ +#ifdef CONFIG_IEEE80211W + sme_event_ch_switch(wpa_s); +#endif /* CONFIG_IEEE80211W */ wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS); + wnm_clear_coloc_intf_reporting(wpa_s); break; +#ifdef CONFIG_AP #ifdef NEED_AP_MLME case EVENT_DFS_RADAR_DETECTED: if (data) - wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event); + wpas_ap_event_dfs_radar_detected(wpa_s, + &data->dfs_event); break; + case EVENT_DFS_NOP_FINISHED: + if (data) + wpas_ap_event_dfs_cac_nop_finished(wpa_s, + &data->dfs_event); + break; +#endif /* NEED_AP_MLME */ +#endif /* CONFIG_AP */ case EVENT_DFS_CAC_STARTED: if (data) wpas_event_dfs_cac_started(wpa_s, &data->dfs_event); @@ -3766,13 +4524,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (data) wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event); break; - case EVENT_DFS_NOP_FINISHED: - if (data) - wpas_event_dfs_cac_nop_finished(wpa_s, - &data->dfs_event); - break; -#endif /* NEED_AP_MLME */ -#endif /* CONFIG_AP */ case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; @@ -3844,6 +4595,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } +#ifdef CONFIG_SAE + if (stype == WLAN_FC_STYPE_AUTH && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) { + sme_external_auth_mgmt_rx( + wpa_s, data->rx_mgmt.frame, + data->rx_mgmt.frame_len); + break; + } +#endif /* CONFIG_SAE */ wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received " "management frame in non-AP mode"); break; @@ -3908,6 +4669,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_OFFCHANNEL */ wpas_p2p_cancel_remain_on_channel_cb( wpa_s, data->remain_on_channel.freq); +#ifdef CONFIG_DPP + wpas_dpp_cancel_remain_on_channel_cb( + wpa_s, data->remain_on_channel.freq); +#endif /* CONFIG_DPP */ break; case EVENT_EAPOL_RX: wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src, @@ -3929,6 +4694,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->signal_change.current_noise, data->signal_change.current_txrate); break; + case EVENT_INTERFACE_MAC_CHANGED: + wpa_supplicant_update_mac_addr(wpa_s); + break; case EVENT_INTERFACE_ENABLED: wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled"); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { @@ -4095,7 +4863,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; case EVENT_WPS_BUTTON_PUSHED: #ifdef CONFIG_WPS - wpas_wps_start_pbc(wpa_s, NULL, 0); + wpas_wps_start_pbc(wpa_s, NULL, 0, 0); #endif /* CONFIG_WPS */ break; case EVENT_AVOID_FREQUENCIES: @@ -4129,12 +4897,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ break; case EVENT_ACS_CHANNEL_SELECTED: +#ifdef CONFIG_AP #ifdef CONFIG_ACS if (!wpa_s->ap_iface) break; hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0], &data->acs_selected_channels); #endif /* CONFIG_ACS */ +#endif /* CONFIG_AP */ break; case EVENT_P2P_LO_STOP: #ifdef CONFIG_P2P @@ -4144,6 +4914,36 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->p2p_lo_stop.reason_code); #endif /* CONFIG_P2P */ break; + case EVENT_BEACON_LOSS: + if (!wpa_s->current_bss || !wpa_s->current_ssid) + break; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS); + bgscan_notify_beacon_loss(wpa_s); + break; + case EVENT_EXTERNAL_AUTH: +#ifdef CONFIG_SAE + if (!wpa_s->current_ssid) { + wpa_printf(MSG_DEBUG, "SAE: current_ssid is NULL"); + break; + } + sme_external_auth_trigger(wpa_s, data); +#endif /* CONFIG_SAE */ + break; + case EVENT_PORT_AUTHORIZED: + wpa_supplicant_event_port_authorized(wpa_s); + break; + case EVENT_STATION_OPMODE_CHANGED: +#ifdef CONFIG_AP + if (!wpa_s->ap_iface || !data) + break; + + hostapd_event_sta_opmode_changed(wpa_s->ap_iface->bss[0], + data->sta_opmode.addr, + data->sta_opmode.smps_mode, + data->sta_opmode.chan_width, + data->sta_opmode.rx_nss); +#endif /* CONFIG_AP */ + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; diff --git a/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py b/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py index 5ac9859f7b72..337519f4e927 100755 --- a/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py +++ b/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py @@ -1,5 +1,6 @@ #!/usr/bin/python +from __future__ import print_function import dbus import sys import time @@ -12,21 +13,24 @@ WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" def usage(): - print "Usage: %s <ifname>" % sys.argv[0] - print "Press Ctrl-C to stop" + print("Usage: %s <ifname>" % sys.argv[0]) + print("Press Ctrl-C to stop") def ProbeRequest(args): if 'addr' in args: - print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']), + print('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']), + end=' ') if 'dst' in args: - print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']), + print('-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']), + end=' ') if 'bssid' in args: - print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']), + print('(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']), + end=' ') if 'signal' in args: - print 'signal:%d' % args['signal'], + print('signal:%d' % args['signal'], end=' ') if 'ies' in args: - print 'have IEs (%d bytes)' % len(args['ies']), - print '' + print('have IEs (%d bytes)' % len(args['ies']), end=' ') + print('') if __name__ == "__main__": global bus diff --git a/contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py b/contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py new file mode 100644 index 000000000000..b468d15cf9cd --- /dev/null +++ b/contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py @@ -0,0 +1,130 @@ +#!/usr/bin/python +# +# Example Android logcat to wpa_supplicant wrapper for QR Code scans +# Copyright (c) 2017, Qualcomm Atheros, Inc. +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import sys +import argparse +import logging +import qrcode + +scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__)) +sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy')) + +import wpaspy + +wpas_ctrl = '/var/run/wpa_supplicant' + +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: + try: + wpas = wpaspy.Ctrl(ctrl) + return wpas + except Exception as e: + pass + return None + +def dpp_logcat(): + for line in iter(sys.stdin.readline, ''): + if "ResultHandler: Launching intent: Intent" not in line: + continue + if "act=android.intent.action.VIEW" not in line: + continue + uri = None + for val in line.split(' '): + if val.startswith('dat='): + uri = val.split('=', 1)[1] + break + if not uri: + continue + if not uri.startswith('DPP:'): + continue + print("Found DPP bootstrap info URI:") + print(uri) + wpas = wpas_connect() + if not wpas: + print("Could not connect to wpa_supplicant") + print('') + continue + res = wpas.request("DPP_QR_CODE " + uri); + try: + id = int(res) + except ValueError: + print("QR Code URI rejected") + continue + print("QR Code URI accepted - ID=%d" % id) + print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id)) + del wpas + +def dpp_display(curve): + wpas = wpas_connect() + if not wpas: + print("Could not connect to wpa_supplicant") + return + res = wpas.request("STATUS") + addr = None + for line in res.splitlines(): + if line.startswith("address="): + addr = line.split('=')[1] + break + cmd = "DPP_BOOTSTRAP_GEN type=qrcode" + cmd += " chan=81/1" + if addr: + cmd += " mac=" + addr.replace(':','') + if curve: + cmd += " curve=" + curve + res = wpas.request(cmd) + try: + id = int(res) + except ValueError: + print("Failed to generate bootstrap info URI") + return + print("Bootstrap information - ID=%d" % id) + print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id)) + uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id) + print(uri) + print("ID=%d" % id) + qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M, + border=3) + qr.add_data(uri, optimize=5) + qr.print_ascii(tty=True) + print("ID=%d" % id) + del wpas + +def main(): + parser = argparse.ArgumentParser(description='Android logcat to wpa_supplicant integration for DPP QR Code operations') + parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, + action='store_const', dest='loglevel', + help='verbose debug output') + parser.add_argument('--curve', '-c', + help='set a specific curve (P-256, P-384, P-521, BP-256R1, BP-384R1, BP-512R1) for key generation') + parser.add_argument('command', choices=['logcat', + 'display'], + nargs='?') + args = parser.parse_args() + + logging.basicConfig(level=args.loglevel) + + if args.command == "logcat": + dpp_logcat() + elif args.command == "display": + dpp_display(args.curve) + +if __name__ == '__main__': + main() diff --git a/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py b/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py index 91eba28908ed..889ac8bff155 100755 --- a/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py @@ -37,7 +37,7 @@ summary_file = None success_file = None def summary(txt): - print txt + print(txt) if summary_file: with open(summary_file, 'a') as f: f.write(txt + "\n") @@ -53,12 +53,12 @@ def wpas_connect(): if os.path.isdir(wpas_ctrl): try: ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] - except OSError, error: - print "Could not find wpa_supplicant: ", error + except OSError as error: + print("Could not find wpa_supplicant: ", error) return None if len(ifaces) < 1: - print "No wpa_supplicant control interface found" + print("No wpa_supplicant control interface found") return None for ctrl in ifaces: @@ -66,10 +66,10 @@ def wpas_connect(): if ifname not in ctrl: continue try: - print "Trying to use control interface " + ctrl + print("Trying to use control interface " + ctrl) wpas = wpaspy.Ctrl(ctrl) return wpas - except Exception, e: + except Exception as e: pass return None @@ -160,30 +160,30 @@ def p2p_handover_client(llc): if (data == None): summary("Could not get handover request carrier record from wpa_supplicant") return - print "Handover request carrier record from wpa_supplicant: " + data.encode("hex") + print("Handover request carrier record from wpa_supplicant: " + data.encode("hex")) datamsg = nfc.ndef.Message(data) message.add_carrier(datamsg[0], "active", datamsg[1:]) global include_wps_req if include_wps_req: - print "Handover request (pre-WPS):" + print("Handover request (pre-WPS):") try: - print message.pretty() - except Exception, e: - print e + print(message.pretty()) + except Exception as e: + print(e) data = wpas_get_handover_req_wps() if data: - print "Add WPS request in addition to P2P" + print("Add WPS request in addition to P2P") datamsg = nfc.ndef.Message(data) message.add_carrier(datamsg[0], "active", datamsg[1:]) - print "Handover request:" + print("Handover request:") try: - print message.pretty() - except Exception, e: - print e - print str(message).encode("hex") + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) client = nfc.handover.HandoverClient(llc) try: @@ -194,7 +194,7 @@ def p2p_handover_client(llc): summary("Handover connection refused") client.close() return - except Exception, e: + except Exception as e: summary("Other exception: " + str(e)) client.close() return @@ -217,41 +217,41 @@ def p2p_handover_client(llc): client.close() return - print "Received message" + print("Received message") try: - print message.pretty() - except Exception, e: - print e - print str(message).encode("hex") + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) message = nfc.ndef.HandoverSelectMessage(message) summary("Handover select received") try: - print message.pretty() - except Exception, e: - print e + print(message.pretty()) + except Exception as e: + print(e) for carrier in message.carriers: - print "Remote carrier type: " + carrier.type + print("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.p2p": - print "P2P carrier type match - send to wpa_supplicant" + print("P2P carrier type match - send to wpa_supplicant") if "OK" in wpas_report_handover(data, carrier.record, "INIT"): success_report("P2P handover reported successfully (initiator)") else: summary("P2P handover report rejected") break - print "Remove peer" + print("Remove peer") client.close() - print "Done with handover" + print("Done with handover") global only_one if only_one: - print "only_one -> stop loop" + print("only_one -> stop loop") global continue_loop continue_loop = False global no_wait if no_wait: - print "Trying to exit.." + print("Trying to exit..") global terminate_now terminate_now = True @@ -283,33 +283,33 @@ class HandoverServer(nfc.handover.HandoverServer): def process_request(self, request): self.ho_server_processing = True clear_raw_mode() - print "HandoverServer - request received" + print("HandoverServer - request received") try: - print "Parsed handover request: " + request.pretty() - except Exception, e: - print e + print("Parsed handover request: " + request.pretty()) + except Exception as e: + print(e) sel = nfc.ndef.HandoverSelectMessage(version="1.2") found = False for carrier in request.carriers: - print "Remote carrier type: " + carrier.type + print("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.p2p": - print "P2P carrier type match - add P2P carrier record" + print("P2P carrier type match - add P2P carrier record") found = True self.received_carrier = carrier.record - print "Carrier record:" + print("Carrier record:") try: - print carrier.record.pretty() - except Exception, e: - print e + print(carrier.record.pretty()) + except Exception as e: + print(e) data = wpas_get_handover_sel() if data is None: - print "Could not get handover select carrier record from wpa_supplicant" + print("Could not get handover select carrier record from wpa_supplicant") continue - print "Handover select carrier record from wpa_supplicant:" - print data.encode("hex") + print("Handover select carrier record from wpa_supplicant:") + print(data.encode("hex")) self.sent_carrier = data if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"): success_report("P2P handover reported successfully (responder)") @@ -324,22 +324,22 @@ class HandoverServer(nfc.handover.HandoverServer): for carrier in request.carriers: if found: break - print "Remote carrier type: " + carrier.type + print("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.wsc": - print "WSC carrier type match - add WSC carrier record" + print("WSC carrier type match - add WSC carrier record") found = True self.received_carrier = carrier.record - print "Carrier record:" + print("Carrier record:") try: - print carrier.record.pretty() - except Exception, e: - print e + print(carrier.record.pretty()) + except Exception as e: + print(e) data = wpas_get_handover_sel_wps() if data is None: - print "Could not get handover select carrier record from wpa_supplicant" + print("Could not get handover select carrier record from wpa_supplicant") continue - print "Handover select carrier record from wpa_supplicant:" - print data.encode("hex") + print("Handover select carrier record from wpa_supplicant:") + print(data.encode("hex")) self.sent_carrier = data if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"): success_report("WSC handover reported successfully") @@ -352,12 +352,12 @@ class HandoverServer(nfc.handover.HandoverServer): found = True break - print "Handover select:" + print("Handover select:") try: - print sel.pretty() - except Exception, e: - print e - print str(sel).encode("hex") + print(sel.pretty()) + except Exception as e: + print(e) + print(str(sel).encode("hex")) summary("Sending handover select") self.success = True @@ -396,7 +396,7 @@ def p2p_tag_read(tag): success = False if len(tag.ndef.message): for record in tag.ndef.message: - print "record type " + record.type + print("record type " + record.type) if record.type == "application/vnd.wfa.wsc": summary("WPS tag - send to wpa_supplicant") success = wpas_tag_read(tag.ndef.message) @@ -419,7 +419,7 @@ def rdwr_connected_p2p_write(tag): global p2p_sel_data tag.ndef.message = str(p2p_sel_data) success_report("Tag write succeeded") - print "Done - remove tag" + print("Done - remove tag") global only_one if only_one: global continue_loop @@ -428,7 +428,7 @@ def rdwr_connected_p2p_write(tag): return p2p_sel_wait_remove def wps_write_p2p_handover_sel(clf, wait_remove=True): - print "Write P2P handover select" + print("Write P2P handover select") data = wpas_get_handover_sel(tag=True) if (data == None): summary("Could not get P2P handover select from wpa_supplicant") @@ -440,14 +440,14 @@ def wps_write_p2p_handover_sel(clf, wait_remove=True): p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2") message = nfc.ndef.Message(data); p2p_sel_data.add_carrier(message[0], "active", message[1:]) - print "Handover select:" + print("Handover select:") try: - print p2p_sel_data.pretty() - except Exception, e: - print e - print str(p2p_sel_data).encode("hex") + print(p2p_sel_data.pretty()) + except Exception as e: + print(e) + print(str(p2p_sel_data).encode("hex")) - print "Touch an NFC tag" + print("Touch an NFC tag") clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write}) @@ -456,11 +456,11 @@ def rdwr_connected(tag): summary("Tag connected: " + str(tag)) if tag.ndef: - print "NDEF tag: " + tag.type + print("NDEF tag: " + tag.type) try: - print tag.ndef.message.pretty() - except Exception, e: - print e + print(tag.ndef.message.pretty()) + except Exception as e: + print(e) success = p2p_tag_read(tag) if only_one and success: global continue_loop @@ -475,15 +475,15 @@ def rdwr_connected(tag): def llcp_worker(llc): global init_on_touch if init_on_touch: - print "Starting handover client" + print("Starting handover client") p2p_handover_client(llc) return global no_input if no_input: - print "Wait for handover to complete" + print("Wait for handover to complete") else: - print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)" + print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)") global srv global wait_connection while not wait_connection and srv.sent_carrier is None: @@ -506,21 +506,21 @@ def llcp_worker(llc): else: continue clear_raw_mode() - print "Starting handover client" + print("Starting handover client") p2p_handover_client(llc) return clear_raw_mode() - print "Exiting llcp_worker thread" + print("Exiting llcp_worker thread") def llcp_startup(clf, llc): - print "Start LLCP server" + print("Start LLCP server") global srv srv = HandoverServer(llc) return llc def llcp_connected(llc): - print "P2P LLCP connected" + print("P2P LLCP connected") global wait_connection wait_connection = False global init_on_touch @@ -587,7 +587,7 @@ def main(): if args.ifname: global ifname ifname = args.ifname - print "Selected ifname " + ifname + print("Selected ifname " + ifname) if args.no_wps_req: global include_wps_req @@ -610,7 +610,7 @@ def main(): try: if not clf.open("usb"): - print "Could not open connection with an NFC device" + print("Could not open connection with an NFC device") raise SystemExit if args.command == "write-p2p-sel": @@ -619,7 +619,7 @@ def main(): global continue_loop while continue_loop: - print "Waiting for a tag or peer to be touched" + print("Waiting for a tag or peer to be touched") wait_connection = True try: if args.tag_read_only: @@ -636,8 +636,8 @@ def main(): 'on-connect': llcp_connected}, terminate=terminate_loop): break - except Exception, e: - print "clf.connect failed" + except Exception as e: + print("clf.connect failed") global srv if only_one and srv and srv.success: diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py index 59b0a9d36462..6e3d94e20ca3 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py @@ -13,40 +13,40 @@ from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> -m <wps_method> \ " \ - % sys.argv[0] - print " -a <addr> [-p <pin>] [-g <go_intent>] \ " - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -m = wps method" - print " -a = peer address" - print " -p = pin number (8 digits)" - print " -g = group owner intent" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> -m <wps_method> \ " \ + % sys.argv[0]) + print(" -a <addr> [-p <pin>] [-g <go_intent>] \ ") + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -m = wps method") + print(" -a = peer address") + print(" -p = pin number (8 digits)") + print(" -g = group owner intent") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]) # Required Signals def GONegotiationSuccess(status): - print "Go Negotiation Success" + print("Go Negotiation Success") def GONegotiationFailure(status): - print 'Go Negotiation Failed. Status:' - print format(status) + print('Go Negotiation Failed. Status:') + print(format(status)) os._exit(0) def GroupStarted(properties): if properties.has_key("group_object"): - print 'Group Formation Complete %s' \ - % properties["group_object"] + print('Group Formation Complete %s' \ + % properties["group_object"]) os._exit(0) def WpsFailure(status, etc): - print "WPS Authentication Failure".format(status) - print etc + print("WPS Authentication Failure".format(status)) + print(etc) os._exit(0) class P2P_Connect(): @@ -118,7 +118,7 @@ class P2P_Connect(): {'Ifname': ifname, 'Driver': 'test'}) time.sleep(1) - except dbus.DBusException, exc: + except dbus.DBusException as exc: if not str(exc).startswith( self.wpas_dbus_interface + \ ".InterfaceExists:"): @@ -157,12 +157,12 @@ class P2P_Connect(): if (self.pin != None): self.p2p_connect_arguements.update({'pin':self.pin}) else: - print "Error:\n Pin required for wps_method=display" + print("Error:\n Pin required for wps_method=display") usage() quit() if (self.go_intent != None and int(self.go_intent) != 15): - print "go_intent overwritten to 15" + print("go_intent overwritten to 15") self.go_intent = '15' @@ -171,14 +171,14 @@ class P2P_Connect(): if (self.pin != None): self.p2p_connect_arguements.update({'pin':self.pin}) else: - print "Error:\n Pin required for wps_method=keypad" + print("Error:\n Pin required for wps_method=keypad") usage() quit() if (self.go_intent != None and int(self.go_intent) == 15): error = "Error :\n Group Owner intent cannot be" + \ " 15 for wps_method=keypad" - print error + print(error) usage() quit() @@ -186,15 +186,15 @@ class P2P_Connect(): # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad elif (self.wps_method == 'pin'): if (self.pin != None): - print "pin ignored" + print("pin ignored") # No pin is required for pbc so it is ignored elif (self.wps_method == 'pbc'): if (self.pin != None): - print "pin ignored" + print("pin ignored") else: - print "Error:\n wps_method not supported or does not exist" + print("Error:\n wps_method not supported or does not exist") usage() quit() @@ -209,12 +209,12 @@ class P2P_Connect(): result_pin = self.p2p_interface.Connect( self.p2p_connect_arguements) - except dbus.DBusException, exc: + except dbus.DBusException as exc: raise exc if (self.wps_method == 'pin' and \ not self.p2p_connect_arguements.has_key('pin') ): - print "Connect return with pin value of %d " % int(result_pin) + print("Connect return with pin value of %d " % int(result_pin)) gobject.MainLoop().run() if __name__ == "__main__": @@ -268,19 +268,19 @@ if __name__ == "__main__": # Required Arguements check if (interface_name == None or wps_method == None or addr == None): - print "Error:\n Required arguements not specified" + print("Error:\n Required arguements not specified") usage() quit() # Group Owner Intent Check if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ): - print "Error:\n Group Owner Intent must be between 0 and 15 inclusive" + print("Error:\n Group Owner Intent must be between 0 and 15 inclusive") usage() quit() # Pin Check if (pin != None and len(pin) != 8): - print "Error:\n Pin is not 8 digits" + print("Error:\n Pin is not 8 digits") usage() quit() @@ -289,7 +289,7 @@ if __name__ == "__main__": addr,pin,wps_method,go_intent) except: - print "Error:\n Invalid Arguements" + print("Error:\n Invalid Arguements") usage() quit() diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py index c3e39b3de285..85b5a8b39f5e 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py @@ -12,19 +12,19 @@ import getopt from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> \ " \ - % sys.argv[0] - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i p2p-wlan0-0" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> \ " \ + % sys.argv[0]) + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i p2p-wlan0-0" % sys.argv[0]) # Required Signals def GroupFinished(status, etc): - print "Disconnected" + print("Disconnected") os._exit(0) class P2P_Disconnect (threading.Thread): @@ -81,10 +81,10 @@ class P2P_Disconnect (threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -142,7 +142,7 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() @@ -152,7 +152,7 @@ if __name__ == "__main__": wpas_dbus_interface,timeout) except: - print "Error:\n Invalid wpas_dbus_interface" + print("Error:\n Invalid wpas_dbus_interface") usage() quit() @@ -165,5 +165,5 @@ if __name__ == "__main__": except: pass - print "Disconnect timed out" + print("Disconnect timed out") quit() diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py index 973d46ab0f4b..e2df52896991 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py @@ -13,23 +13,23 @@ import getopt from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> [-t <timeout>] \ " \ - % sys.argv[0] - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -t = timeout = 0s (infinite)" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i wlan0 -t 10" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> [-t <timeout>] \ " \ + % sys.argv[0]) + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -t = timeout = 0s (infinite)") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0 -t 10" % sys.argv[0]) # Required Signals def deviceFound(devicepath): - print "Device found: %s" % (devicepath) + print("Device found: %s" % (devicepath)) def deviceLost(devicepath): - print "Device lost: %s" % (devicepath) + print("Device lost: %s" % (devicepath)) class P2P_Find (threading.Thread): # Needed Variables @@ -85,10 +85,10 @@ class P2P_Find (threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -150,7 +150,7 @@ if __name__ == "__main__": if ( int(value) >= 0): timeout = value else: - print "Error:\n Timeout cannot be negative" + print("Error:\n Timeout cannot be negative") usage() quit() # Dbus interface @@ -161,7 +161,7 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() @@ -170,7 +170,7 @@ if __name__ == "__main__": p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout) except: - print "Error:\n Invalid wpas_dbus_interface" + print("Error:\n Invalid wpas_dbus_interface") usage() quit() diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py index ff8509d6053d..42fc7a3e915a 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py @@ -13,19 +13,19 @@ import getopt from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> \ " \ - % sys.argv[0] - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i wlan0" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> \ " \ + % sys.argv[0]) + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0" % sys.argv[0]) # Required Signals\ def deviceLost(devicepath): - print "Device lost: %s" % (devicepath) + print("Device lost: %s" % (devicepath)) class P2P_Flush (threading.Thread): # Needed Variables @@ -81,10 +81,10 @@ class P2P_Flush (threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -142,7 +142,7 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() @@ -151,7 +151,7 @@ if __name__ == "__main__": p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout) except: - print "Error:\n Invalid wpas_dbus_interface" + print("Error:\n Invalid wpas_dbus_interface") usage() quit() @@ -164,5 +164,5 @@ if __name__ == "__main__": except: pass - print "p2p_flush complete" + print("p2p_flush complete") quit() diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py index 5c8fdafdfd9a..6d408218a25e 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py @@ -11,30 +11,30 @@ import threading from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> [-p <persistent>] \ " \ - % sys.argv[0] - print " [-f <frequency>] [-o <group_object_path>] \ " - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -p = persistant group = 0 (0=false, 1=true)" - print " -f = frequency" - print " -o = persistent group object path" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i wlan0" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> [-p <persistent>] \ " \ + % sys.argv[0]) + print(" [-f <frequency>] [-o <group_object_path>] \ ") + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -p = persistant group = 0 (0=false, 1=true)") + print(" -f = frequency") + print(" -o = persistent group object path") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0" % sys.argv[0]) # Required Signals def GroupStarted(properties): if properties.has_key("group_object"): - print 'Group Formation Complete %s' \ - % properties["group_object"] + print('Group Formation Complete %s' \ + % properties["group_object"]) os._exit(0) def WpsFailure(status, etc): - print "WPS Authentication Failure".format(status) - print etc + print("WPS Authentication Failure".format(status)) + print(etc) os._exit(0) class P2P_Group_Add (threading.Thread): @@ -99,10 +99,10 @@ class P2P_Group_Add (threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -127,7 +127,7 @@ class P2P_Group_Add (threading.Thread): if (int(self.frequency) > 0): self.P2PDictionary.update({'frequency':int(self.frequency)}) else: - print "Error:\n Frequency must be greater than 0" + print("Error:\n Frequency must be greater than 0") usage() os._exit(0) @@ -141,7 +141,7 @@ class P2P_Group_Add (threading.Thread): self.p2p_interface.GroupAdd(self.P2PDictionary) except: - print "Error:\n Could not preform group add" + print("Error:\n Could not preform group add") usage() os._exit(0) @@ -188,7 +188,7 @@ if __name__ == "__main__": elif (value == '1'): persistent = True else: - print "Error:\n Persistent can only be 1 or 0" + print("Error:\n Persistent can only be 1 or 0") usage() os._exit(0) # Frequency @@ -205,7 +205,7 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() @@ -213,10 +213,10 @@ if __name__ == "__main__": p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface, persistent,frequency,persistent_group_object) except: - print "Error:\n Invalid Arguements" + print("Error:\n Invalid Arguements") p2p_group_add_test.constructArguements() p2p_group_add_test.start() time.sleep(5) - print "Error:\n Group formation timed out" + print("Error:\n Group formation timed out") os._exit(0) diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py index 6deb397eca83..341dcd0a983d 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py @@ -11,29 +11,29 @@ import threading from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> -a <addr> \ " \ - % sys.argv[0] - print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -a = address of peer" - print " -o = persistent group object path" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> -a <addr> \ " \ + % sys.argv[0]) + print(" [-o <persistent_group_object>] [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -a = address of peer") + print(" -o = persistent group object path") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]) # Required Signals def InvitationResult(invite_result): - print "Inviation Result signal :" + print("Inviation Result signal :") status = invite_result['status'] - print "status = ", status + print("status = ", status) if invite_result.has_key('BSSID'): bssid = invite_result['BSSID'] - print "BSSID = ", hex(bssid[0]) , ":" , \ + print("BSSID = ", hex(bssid[0]) , ":" , \ hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \ hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \ - hex(bssid[5]) + hex(bssid[5])) os._exit(0) class P2P_Invite (threading.Thread): @@ -96,10 +96,10 @@ class P2P_Invite (threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -127,7 +127,7 @@ class P2P_Invite (threading.Thread): self.p2p_interface.Invite(self.P2PDictionary) except: - print "Error:\n Invalid Arguements" + print("Error:\n Invalid Arguements") usage() os._exit(0) @@ -176,12 +176,12 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() if (addr == None): - print "Error:\n peer address is required" + print("Error:\n peer address is required") usage() quit() @@ -190,12 +190,12 @@ if __name__ == "__main__": P2P_Invite(interface_name,wpas_dbus_interface, addr,persistent_group_object) except: - print "Error:\n Invalid Arguements" + print("Error:\n Invalid Arguements") usage() os._exit(1) p2p_invite_test.constructArguements() p2p_invite_test.start() time.sleep(10) - print "Error:\n p2p_invite timed out" + print("Error:\n p2p_invite timed out") os._exit(0) diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py index bb3c1e49d5f1..b0837d9df5d2 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py @@ -13,20 +13,20 @@ import getopt from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> [-t <timeout>] \ " \ - % sys.argv[0] - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -t = timeout = 0s (infinite)" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i wlan0 -t 5" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> [-t <timeout>] \ " \ + % sys.argv[0]) + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -t = timeout = 0s (infinite)") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0 -t 5" % sys.argv[0]) # Required Signals def p2pStateChange(status): - print status + print(status) class P2P_Listen(threading.Thread): # Needed Variables @@ -82,10 +82,10 @@ class P2P_Listen(threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -140,7 +140,7 @@ if __name__ == "__main__": if ( int(value) >= 0): timeout = value else: - print "Error:\n Timeout cannot be negative" + print("Error:\n Timeout cannot be negative") usage() quit() # Dbus interface @@ -151,7 +151,7 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() @@ -160,7 +160,7 @@ if __name__ == "__main__": p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout) except: - print "Error:\n Invalid wpas_dbus_interface" + print("Error:\n Invalid wpas_dbus_interface") usage() quit() diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py index f6c03b027228..bdb4c0e3221d 100644 --- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py +++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py @@ -11,22 +11,22 @@ import getopt from dbus.mainloop.glib import DBusGMainLoop def usage(): - print "Usage:" - print " %s -i <interface_name> \ " \ - % sys.argv[0] - print " [-w <wpas_dbus_interface>]" - print "Options:" - print " -i = interface name" - print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" - print "Example:" - print " %s -i wlan0" % sys.argv[0] + print("Usage:") + print(" %s -i <interface_name> \ " \ + % sys.argv[0]) + print(" [-w <wpas_dbus_interface>]") + print("Options:") + print(" -i = interface name") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0" % sys.argv[0]) # Required Signals def deviceLost(devicepath): - print "Device lost: %s" % (devicepath) + print("Device lost: %s" % (devicepath)) def p2pStateChange(status): - print status + print(status) os._exit(0) class P2P_Stop_Find (threading.Thread): @@ -83,10 +83,10 @@ class P2P_Stop_Find (threading.Thread): try: self.path = self.wpas.GetInterface( self.interface_name) - except dbus.DBusException, exc: + except dbus.DBusException as exc: error = 'Error:\n Interface ' + self.interface_name \ + ' was not found' - print error + print(error) usage() os._exit(0) @@ -147,7 +147,7 @@ if __name__ == "__main__": # Interface name is required and was not given if (interface_name == None): - print "Error:\n interface_name is required" + print("Error:\n interface_name is required") usage() quit() @@ -157,7 +157,7 @@ if __name__ == "__main__": wpas_dbus_interface,timeout) except: - print "Error:\n Invalid wpas_dbus_interface" + print("Error:\n Invalid wpas_dbus_interface") usage() quit() @@ -170,5 +170,5 @@ if __name__ == "__main__": except: pass - print "p2p find stopped" + print("p2p find stopped") quit() diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py index 03da187c8908..732f54d20f8b 100755 --- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py +++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py @@ -11,8 +11,8 @@ def main(): "/fi/w1/wpa_supplicant1") props = wpas_obj.GetAll("fi.w1.wpa_supplicant1", dbus_interface=dbus.PROPERTIES_IFACE) - print "GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):" - print props + print("GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):") + print(props) if len(sys.argv) != 2: os._exit(1) @@ -24,15 +24,15 @@ def main(): if_obj = bus.get_object("fi.w1.wpa_supplicant1", path) props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface", dbus_interface=dbus.PROPERTIES_IFACE) - print - print "GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path) - print props + print('') + print("GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path)) + print(props) props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface.WPS", dbus_interface=dbus.PROPERTIES_IFACE) - print - print "GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path) - print props + print('') + print("GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path)) + print(props) res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'BSSs', dbus_interface=dbus.PROPERTIES_IFACE) @@ -40,9 +40,9 @@ def main(): bss_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0]) props = bss_obj.GetAll("fi.w1.wpa_supplicant1.BSS", dbus_interface=dbus.PROPERTIES_IFACE) - print - print "GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0]) - print props + print('') + print("GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0])) + print(props) res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'Networks', dbus_interface=dbus.PROPERTIES_IFACE) @@ -50,10 +50,9 @@ def main(): net_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0]) props = net_obj.GetAll("fi.w1.wpa_supplicant1.Network", dbus_interface=dbus.PROPERTIES_IFACE) - print - print "GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0]) - print props + print('') + print("GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0])) + print(props) if __name__ == "__main__": main() - diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py index d90ef1878ca7..366a65546af6 100755 --- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py +++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py @@ -32,17 +32,17 @@ def list_interfaces(wpas_obj): if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname', dbus_interface=dbus.PROPERTIES_IFACE) - print ifname + print(ifname) def interfaceAdded(interface, properties): - print "InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname']) + print("InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])) def interfaceRemoved(interface): - print "InterfaceRemoved(%s)" % (interface) + print("InterfaceRemoved(%s)" % (interface)) def propertiesChanged(properties): for i in properties: - print "PropertiesChanged: %s=%s" % (i, properties[i]) + print("PropertiesChanged: %s=%s" % (i, properties[i])) def showBss(bss): net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss) @@ -80,48 +80,48 @@ def showBss(bss): else: maxrate = 0 - print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq) + print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)) def scanDone(success): gobject.MainLoop().quit() - print "Scan done: success=%s" % success + print("Scan done: success=%s" % success) def scanDone2(success, path=None): - print "Scan done: success=%s [path=%s]" % (success, path) + print("Scan done: success=%s [path=%s]" % (success, path)) def bssAdded(bss, properties): - print "BSS added: %s" % (bss) + print("BSS added: %s" % (bss)) showBss(bss) def bssRemoved(bss): - print "BSS removed: %s" % (bss) + print("BSS removed: %s" % (bss)) def blobAdded(blob): - print "BlobAdded(%s)" % (blob) + print("BlobAdded(%s)" % (blob)) def blobRemoved(blob): - print "BlobRemoved(%s)" % (blob) + print("BlobRemoved(%s)" % (blob)) def networkAdded(network, properties): - print "NetworkAdded(%s)" % (network) + print("NetworkAdded(%s)" % (network)) def networkRemoved(network): - print "NetworkRemoved(%s)" % (network) + print("NetworkRemoved(%s)" % (network)) def networkSelected(network): - print "NetworkSelected(%s)" % (network) + print("NetworkSelected(%s)" % (network)) def propertiesChangedInterface(properties): for i in properties: - print "PropertiesChanged(interface): %s=%s" % (i, properties[i]) + print("PropertiesChanged(interface): %s=%s" % (i, properties[i])) def propertiesChangedBss(properties): for i in properties: - print "PropertiesChanged(BSS): %s=%s" % (i, properties[i]) + print("PropertiesChanged(BSS): %s=%s" % (i, properties[i])) def propertiesChangedNetwork(properties): for i in properties: - print "PropertiesChanged(Network): %s=%s" % (i, properties[i]) + print("PropertiesChanged(Network): %s=%s" % (i, properties[i])) def main(): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py index b8863858fe8c..7d87b1efd5dc 100755 --- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py +++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py @@ -15,23 +15,23 @@ WPAS_DBUS_WPS_INTERFACE = "fi.w1.wpa_supplicant1.Interface.WPS" def propertiesChanged(properties): if properties.has_key("State"): - print "PropertiesChanged: State: %s" % (properties["State"]) + print("PropertiesChanged: State: %s" % (properties["State"])) def scanDone(success): - print "Scan done: success=%s" % success + print("Scan done: success=%s" % success) def bssAdded(bss, properties): - print "BSS added: %s" % (bss) + print("BSS added: %s" % (bss)) def bssRemoved(bss): - print "BSS removed: %s" % (bss) + print("BSS removed: %s" % (bss)) def wpsEvent(name, args): - print "WPS event: %s" % (name) - print args + print("WPS event: %s" % (name)) + print(args) def credentials(cred): - print "WPS credentials: %s" % (cred) + print("WPS credentials: %s" % (cred)) def main(): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) @@ -40,7 +40,7 @@ def main(): wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) if len(sys.argv) != 2: - print "Missing ifname argument" + print("Missing ifname argument") os._exit(1) wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py index 25072ce9a2df..6bf74ae44122 100755 --- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py +++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py @@ -31,11 +31,11 @@ def list_interfaces(wpas_obj): if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname', dbus_interface=dbus.PROPERTIES_IFACE) - print ifname + print(ifname) def propertiesChanged(properties): if properties.has_key("State"): - print "PropertiesChanged: State: %s" % (properties["State"]) + print("PropertiesChanged: State: %s" % (properties["State"])) def showBss(bss): net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss) @@ -73,25 +73,25 @@ def showBss(bss): else: maxrate = 0 - print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq) + print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)) def scanDone(success): - print "Scan done: success=%s" % success + print("Scan done: success=%s" % success) res = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'BSSs', dbus_interface=dbus.PROPERTIES_IFACE) - print "Scanned wireless networks:" + print("Scanned wireless networks:") for opath in res: - print opath + print(opath) showBss(opath) def bssAdded(bss, properties): - print "BSS added: %s" % (bss) + print("BSS added: %s" % (bss)) showBss(bss) def bssRemoved(bss): - print "BSS removed: %s" % (bss) + print("BSS removed: %s" % (bss)) def main(): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) @@ -123,14 +123,14 @@ def main(): path = None try: path = wpas.GetInterface(ifname) - except dbus.DBusException, exc: + except dbus.DBusException as exc: if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceUnknown:"): raise exc try: path = wpas.CreateInterface({'Ifname': ifname, 'Driver': 'test'}) time.sleep(1) - except dbus.DBusException, exc: + except dbus.DBusException as exc: if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceExists:"): raise exc diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-test.py b/contrib/wpa/wpa_supplicant/examples/wpas-test.py deleted file mode 100755 index fd7f73d428b8..000000000000 --- a/contrib/wpa/wpa_supplicant/examples/wpas-test.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/python - -import dbus -import sys, os -import time - -WPAS_DBUS_SERVICE = "fi.epitest.hostap.WPASupplicant" -WPAS_DBUS_INTERFACE = "fi.epitest.hostap.WPASupplicant" -WPAS_DBUS_OPATH = "/fi/epitest/hostap/WPASupplicant" - -WPAS_DBUS_INTERFACES_INTERFACE = "fi.epitest.hostap.WPASupplicant.Interface" -WPAS_DBUS_INTERFACES_OPATH = "/fi/epitest/hostap/WPASupplicant/Interfaces" -WPAS_DBUS_BSSID_INTERFACE = "fi.epitest.hostap.WPASupplicant.BSSID" - -def byte_array_to_string(s): - import urllib - r = "" - for c in s: - if c >= 32 and c < 127: - r += "%c" % c - else: - r += urllib.quote(chr(c)) - return r - -def main(): - if len(sys.argv) != 2: - print "Usage: wpas-test.py <interface>" - os._exit(1) - - ifname = sys.argv[1] - - bus = dbus.SystemBus() - wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) - wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) - - # See if wpa_supplicant already knows about this interface - path = None - try: - path = wpas.getInterface(ifname) - except dbus.dbus_bindings.DBusException, exc: - if str(exc) != "wpa_supplicant knows nothing about this interface.": - raise exc - try: - path = wpas.addInterface(ifname, {'driver': dbus.Variant('wext')}) - except dbus.dbus_bindings.DBusException, exc: - if str(exc) != "wpa_supplicant already controls this interface.": - raise exc - - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) - iface.scan() - # Should really wait for the "scanResults" signal instead of sleeping - time.sleep(5) - res = iface.scanResults() - - print "Scanned wireless networks:" - for opath in res: - net_obj = bus.get_object(WPAS_DBUS_SERVICE, opath) - net = dbus.Interface(net_obj, WPAS_DBUS_BSSID_INTERFACE) - props = net.properties() - - # Convert the byte-array for SSID and BSSID to printable strings - bssid = "" - for item in props["bssid"]: - bssid = bssid + ":%02x" % item - bssid = bssid[1:] - ssid = byte_array_to_string(props["ssid"]) - wpa = "no" - if props.has_key("wpaie"): - wpa = "yes" - wpa2 = "no" - if props.has_key("rsnie"): - wpa2 = "yes" - freq = 0 - if props.has_key("frequency"): - freq = props["frequency"] - caps = props["capabilities"] - qual = props["quality"] - level = props["level"] - noise = props["noise"] - maxrate = props["maxrate"] / 1000000 - - print " %s :: ssid='%s' wpa=%s wpa2=%s quality=%d%% rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, qual, maxrate, freq) - - wpas.removeInterface(dbus.ObjectPath(path)) - # Should fail here with unknown interface error - iface.scan() - -if __name__ == "__main__": - main() - diff --git a/contrib/wpa/wpa_supplicant/examples/wps-ap-cli b/contrib/wpa/wpa_supplicant/examples/wps-ap-cli index cc2cff2ebc24..15d913ef1fae 100755 --- a/contrib/wpa/wpa_supplicant/examples/wps-ap-cli +++ b/contrib/wpa/wpa_supplicant/examples/wps-ap-cli @@ -14,12 +14,12 @@ pbc() enter_pin() { echo "Enter a PIN from a station to be enrolled to the network." - echo -n "Enrollee PIN: " + printf "Enrollee PIN: " read pin cpin=`$CLI wps_check_pin "$pin" | tail -1` if [ "$cpin" = "FAIL-CHECKSUM" ]; then echo "Checksum digit is not valid" - echo -n "Do you want to use this PIN (y/n)? " + printf "Do you want to use this PIN (y/n)? " read resp case "$resp" in y*) @@ -52,7 +52,7 @@ main_menu() echo "3: Show current configuration" echo "0: Exit wps-ap-cli" - echo -n "Command: " + printf "Command: " read cmd case "$cmd" in diff --git a/contrib/wpa/wpa_supplicant/examples/wps-nfc.py b/contrib/wpa/wpa_supplicant/examples/wps-nfc.py index 7459eb9ae574..bb458fb37a84 100755 --- a/contrib/wpa/wpa_supplicant/examples/wps-nfc.py +++ b/contrib/wpa/wpa_supplicant/examples/wps-nfc.py @@ -30,7 +30,7 @@ summary_file = None success_file = None def summary(txt): - print txt + print(txt) if summary_file: with open(summary_file, 'a') as f: f.write(txt + "\n") @@ -46,19 +46,19 @@ def wpas_connect(): if os.path.isdir(wpas_ctrl): try: ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] - except OSError, error: - print "Could not find wpa_supplicant: ", error + except OSError as error: + print("Could not find wpa_supplicant: ", error) return None if len(ifaces) < 1: - print "No wpa_supplicant control interface found" + print("No wpa_supplicant control interface found") return None for ctrl in ifaces: try: wpas = wpaspy.Ctrl(ctrl) return wpas - except Exception, e: + except Exception as e: pass return None @@ -163,22 +163,22 @@ class HandoverServer(nfc.handover.HandoverServer): self.ho_server_processing = True summary("HandoverServer - request received") try: - print "Parsed handover request: " + request.pretty() - except Exception, e: - print e + print("Parsed handover request: " + request.pretty()) + except Exception as e: + print(e) sel = nfc.ndef.HandoverSelectMessage(version="1.2") for carrier in request.carriers: - print "Remote carrier type: " + carrier.type + print("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.wsc": summary("WPS carrier type match - add WPS carrier record") data = wpas_get_handover_sel(self.uuid) if data is None: summary("Could not get handover select carrier record from wpa_supplicant") continue - print "Handover select carrier record from wpa_supplicant:" - print data.encode("hex") + print("Handover select carrier record from wpa_supplicant:") + print(data.encode("hex")) self.sent_carrier = data if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"): success_report("Handover reported successfully (responder)") @@ -188,12 +188,12 @@ class HandoverServer(nfc.handover.HandoverServer): message = nfc.ndef.Message(data); sel.add_carrier(message[0], "active", message[1:]) - print "Handover select:" + print("Handover select:") try: - print sel.pretty() - except Exception, e: - print e - print str(sel).encode("hex") + print(sel.pretty()) + except Exception as e: + print(e) + print(str(sel).encode("hex")) summary("Sending handover select") self.success = True @@ -207,19 +207,19 @@ def wps_handover_init(llc): if (data == None): summary("Could not get handover request carrier record from wpa_supplicant") return - print "Handover request carrier record from wpa_supplicant: " + data.encode("hex") + print("Handover request carrier record from wpa_supplicant: " + data.encode("hex")) message = nfc.ndef.HandoverRequestMessage(version="1.2") message.nonce = random.randint(0, 0xffff) datamsg = nfc.ndef.Message(data) message.add_carrier(datamsg[0], "active", datamsg[1:]) - print "Handover request:" + print("Handover request:") try: - print message.pretty() - except Exception, e: - print e - print str(message).encode("hex") + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) client = nfc.handover.HandoverClient(llc) try: @@ -230,7 +230,7 @@ def wps_handover_init(llc): summary("Handover connection refused") client.close() return - except Exception, e: + except Exception as e: summary("Other exception: " + str(e)) client.close() return @@ -253,23 +253,23 @@ def wps_handover_init(llc): client.close() return - print "Received message" + print("Received message") try: - print message.pretty() - except Exception, e: - print e - print str(message).encode("hex") + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) message = nfc.ndef.HandoverSelectMessage(message) summary("Handover select received") try: - print message.pretty() - except Exception, e: - print e + print(message.pretty()) + except Exception as e: + print(e) for carrier in message.carriers: - print "Remote carrier type: " + carrier.type + print("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.wsc": - print "WPS carrier type match - send to wpa_supplicant" + print("WPS carrier type match - send to wpa_supplicant") if "OK" in wpas_report_handover(data, carrier.record, "INIT"): success_report("Handover reported successfully (initiator)") else: @@ -278,9 +278,9 @@ def wps_handover_init(llc): #wifi = nfc.ndef.WifiConfigRecord(carrier.record) #print wifi.pretty() - print "Remove peer" + print("Remove peer") client.close() - print "Done with handover" + print("Done with handover") global only_one if only_one: global continue_loop @@ -288,7 +288,7 @@ def wps_handover_init(llc): global no_wait if no_wait: - print "Trying to exit.." + print("Trying to exit..") global terminate_now terminate_now = True @@ -296,7 +296,7 @@ def wps_tag_read(tag, wait_remove=True): success = False if len(tag.ndef.message): for record in tag.ndef.message: - print "record type " + record.type + print("record type " + record.type) if record.type == "application/vnd.wfa.wsc": summary("WPS tag - send to wpa_supplicant") success = wpas_tag_read(tag.ndef.message) @@ -308,7 +308,7 @@ def wps_tag_read(tag, wait_remove=True): success_report("Tag read succeeded") if wait_remove: - print "Remove tag" + print("Remove tag") while tag.is_present: time.sleep(0.1) @@ -320,7 +320,7 @@ def rdwr_connected_write(tag): global write_data tag.ndef.message = str(write_data) success_report("Tag write succeeded") - print "Done - remove tag" + print("Done - remove tag") global only_one if only_one: global continue_loop @@ -330,41 +330,41 @@ def rdwr_connected_write(tag): time.sleep(0.1) def wps_write_config_tag(clf, id=None, wait_remove=True): - print "Write WPS config token" + print("Write WPS config token") global write_data, write_wait_remove write_wait_remove = wait_remove write_data = wpas_get_config_token(id) if write_data == None: - print "Could not get WPS config token from wpa_supplicant" + print("Could not get WPS config token from wpa_supplicant") sys.exit(1) return - print "Touch an NFC tag" + print("Touch an NFC tag") clf.connect(rdwr={'on-connect': rdwr_connected_write}) def wps_write_er_config_tag(clf, uuid, wait_remove=True): - print "Write WPS ER config token" + print("Write WPS ER config token") global write_data, write_wait_remove write_wait_remove = wait_remove write_data = wpas_get_er_config_token(uuid) if write_data == None: - print "Could not get WPS config token from wpa_supplicant" + print("Could not get WPS config token from wpa_supplicant") return - print "Touch an NFC tag" + print("Touch an NFC tag") clf.connect(rdwr={'on-connect': rdwr_connected_write}) def wps_write_password_tag(clf, wait_remove=True): - print "Write WPS password token" + print("Write WPS password token") global write_data, write_wait_remove write_wait_remove = wait_remove write_data = wpas_get_password_token() if write_data == None: - print "Could not get WPS password token from wpa_supplicant" + print("Could not get WPS password token from wpa_supplicant") return - print "Touch an NFC tag" + print("Touch an NFC tag") clf.connect(rdwr={'on-connect': rdwr_connected_write}) @@ -373,11 +373,11 @@ def rdwr_connected(tag): summary("Tag connected: " + str(tag)) if tag.ndef: - print "NDEF tag: " + tag.type + print("NDEF tag: " + tag.type) try: - print tag.ndef.message.pretty() - except Exception, e: - print e + print(tag.ndef.message.pretty()) + except Exception as e: + print(e) success = wps_tag_read(tag, not only_one) if only_one and success: global continue_loop @@ -393,7 +393,7 @@ def llcp_worker(llc): global arg_uuid if arg_uuid is None: wps_handover_init(llc) - print "Exiting llcp_worker thread" + print("Exiting llcp_worker thread") return global srv @@ -405,19 +405,19 @@ def llcp_worker(llc): def llcp_startup(clf, llc): global arg_uuid if arg_uuid: - print "Start LLCP server" + print("Start LLCP server") global srv srv = HandoverServer(llc) if arg_uuid is "ap": - print "Trying to handle WPS handover" + print("Trying to handle WPS handover") srv.uuid = None else: - print "Trying to handle WPS handover with AP " + arg_uuid + print("Trying to handle WPS handover with AP " + arg_uuid) srv.uuid = arg_uuid return llc def llcp_connected(llc): - print "P2P LLCP connected" + print("P2P LLCP connected") global wait_connection wait_connection = False global arg_uuid @@ -426,7 +426,7 @@ def llcp_connected(llc): srv.start() else: threading.Thread(target=llcp_worker, args=(llc,)).start() - print "llcp_connected returning" + print("llcp_connected returning") return True @@ -482,7 +482,7 @@ def main(): try: if not clf.open("usb"): - print "Could not open connection with an NFC device" + print("Could not open connection with an NFC device") raise SystemExit if args.command == "write-config": @@ -499,7 +499,7 @@ def main(): global continue_loop while continue_loop: - print "Waiting for a tag or peer to be touched" + print("Waiting for a tag or peer to be touched") wait_connection = True try: if not clf.connect(rdwr={'on-connect': rdwr_connected}, @@ -507,8 +507,8 @@ def main(): 'on-connect': llcp_connected}, terminate=terminate_loop): break - except Exception, e: - print "clf.connect failed" + except Exception as e: + print("clf.connect failed") global srv if only_one and srv and srv.success: diff --git a/contrib/wpa/wpa_supplicant/gas_query.c b/contrib/wpa/wpa_supplicant/gas_query.c index 691de0345d13..8e977a3eccb3 100644 --- a/contrib/wpa/wpa_supplicant/gas_query.c +++ b/contrib/wpa/wpa_supplicant/gas_query.c @@ -42,6 +42,7 @@ struct gas_query_pending { unsigned int wait_comeback:1; unsigned int offchannel_tx_started:1; unsigned int retry:1; + unsigned int wildcard_bssid:1; int freq; u16 status_code; struct wpabuf *req; @@ -53,6 +54,7 @@ struct gas_query_pending { const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code); void *ctx; + u8 sa[ETH_ALEN]; }; /** @@ -63,6 +65,9 @@ struct gas_query { struct dl_list pending; /* struct gas_query_pending */ struct gas_query_pending *current; struct wpa_radio_work *work; + struct os_reltime last_mac_addr_rand; + int last_rand_sa_type; + u8 rand_addr[ETH_ALEN]; }; @@ -117,6 +122,8 @@ static const char * gas_result_txt(enum gas_query_result result) return "PEER_ERROR"; case GAS_QUERY_INTERNAL_ERROR: return "INTERNAL_ERROR"; + case GAS_QUERY_STOPPED: + return "STOPPED"; case GAS_QUERY_DELETED_AT_DEINIT: return "DELETED_AT_DEINIT"; } @@ -239,10 +246,17 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, } os_get_reltime(&query->last_oper); - if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) { + if (result == OFFCHANNEL_SEND_ACTION_SUCCESS || + result == OFFCHANNEL_SEND_ACTION_NO_ACK) { eloop_cancel_timeout(gas_query_timeout, gas, query); - eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, - gas_query_timeout, gas, query); + if (result == OFFCHANNEL_SEND_ACTION_NO_ACK) { + wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request"); + eloop_register_timeout(0, 250000, + gas_query_timeout, gas, query); + } else { + eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, + gas_query_timeout, gas, query); + } if (query->wait_comeback && !query->retry) { eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); @@ -258,7 +272,7 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, } -static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) +int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) { if (wpa_s->current_ssid == NULL || wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || @@ -278,8 +292,9 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, }; wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " - "freq=%d prot=%d", MAC2STR(query->addr), - (unsigned int) wpabuf_len(req), query->freq, prot); + "freq=%d prot=%d using src addr " MACSTR, + MAC2STR(query->addr), (unsigned int) wpabuf_len(req), + query->freq, prot, MAC2STR(query->sa)); if (prot) { u8 *categ = wpabuf_mhead_u8(req); *categ = WLAN_ACTION_PROTECTED_DUAL; @@ -288,17 +303,20 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, if (gas->wpa_s->max_remain_on_chan && wait_time > gas->wpa_s->max_remain_on_chan) wait_time = gas->wpa_s->max_remain_on_chan; - if (!gas->wpa_s->conf->gas_address3 || - (gas->wpa_s->current_ssid && - gas->wpa_s->wpa_state >= WPA_ASSOCIATED && - os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0)) + if (!query->wildcard_bssid && + (!gas->wpa_s->conf->gas_address3 || + (gas->wpa_s->current_ssid && + gas->wpa_s->wpa_state >= WPA_ASSOCIATED && + os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))) bssid = query->addr; else bssid = wildcard_bssid; + res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, - gas->wpa_s->own_addr, bssid, - wpabuf_head(req), wpabuf_len(req), - wait_time, gas_query_tx_status, 0); + query->sa, bssid, wpabuf_head(req), + wpabuf_len(req), wait_time, + gas_query_tx_status, 0); + if (res == 0) query->offchannel_tx_started = 1; return res; @@ -407,6 +425,7 @@ static void gas_query_rx_initial(struct gas_query *gas, } if (comeback_delay) { + eloop_cancel_timeout(gas_query_timeout, gas, query); query->wait_comeback = 1; gas_query_tx_comeback_req_delay(gas, query, comeback_delay); return; @@ -724,6 +743,58 @@ static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) } +static int gas_query_set_sa(struct gas_query *gas, + struct gas_query_pending *query) +{ + struct wpa_supplicant *wpa_s = gas->wpa_s; + struct os_reltime now; + + if (!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 */ + os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN); + return 0; + } + + os_get_reltime(&now); + + if (wpa_s->conf->gas_rand_mac_addr == gas->last_rand_sa_type && + gas->last_mac_addr_rand.sec != 0 && + !os_reltime_expired(&now, &gas->last_mac_addr_rand, + wpa_s->conf->gas_rand_addr_lifetime)) { + wpa_printf(MSG_DEBUG, + "GAS: Use the previously selected random transmitter address " + MACSTR, MAC2STR(gas->rand_addr)); + os_memcpy(query->sa, gas->rand_addr, ETH_ALEN); + return 0; + } + + if (wpa_s->conf->gas_rand_mac_addr == 1 && + random_mac_addr(gas->rand_addr) < 0) { + wpa_printf(MSG_ERROR, "GAS: Failed to get random address"); + return -1; + } + + if (wpa_s->conf->gas_rand_mac_addr == 2 && + random_mac_addr_keep_oui(gas->rand_addr) < 0) { + wpa_printf(MSG_ERROR, + "GAS: Failed to get random address with same OUI"); + return -1; + } + + wpa_printf(MSG_DEBUG, "GAS: Use a new random transmitter address " + MACSTR, MAC2STR(gas->rand_addr)); + os_memcpy(query->sa, gas->rand_addr, ETH_ALEN); + os_get_reltime(&gas->last_mac_addr_rand); + gas->last_rand_sa_type = wpa_s->conf->gas_rand_mac_addr; + + return 0; +} + + /** * gas_query_req - Request a GAS query * @gas: GAS query data from gas_query_init() @@ -736,7 +807,7 @@ static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) * Returns: dialog token (>= 0) on success or -1 on failure */ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, - struct wpabuf *req, + int wildcard_bssid, struct wpabuf *req, void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, @@ -758,8 +829,13 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, return -1; query->gas = gas; + if (gas_query_set_sa(gas, query)) { + os_free(query); + return -1; + } os_memcpy(query->addr, dst, ETH_ALEN); query->dialog_token = dialog_token; + query->wildcard_bssid = !!wildcard_bssid; query->freq = freq; query->cb = cb; query->ctx = ctx; @@ -781,3 +857,27 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, return dialog_token; } + + +int gas_query_stop(struct gas_query *gas, u8 dialog_token) +{ + struct gas_query_pending *query; + + dl_list_for_each(query, &gas->pending, struct gas_query_pending, list) { + if (query->dialog_token == dialog_token) { + if (!gas->work) { + /* The pending radio work has not yet been + * started, but the pending entry has a + * reference to the soon to be freed query. + * Need to remove that radio work now to avoid + * leaving behind a reference to freed memory. + */ + radio_remove_pending_work(gas->wpa_s, query); + } + gas_query_done(gas, query, GAS_QUERY_STOPPED); + return 0; + } + } + + return -1; +} diff --git a/contrib/wpa/wpa_supplicant/gas_query.h b/contrib/wpa/wpa_supplicant/gas_query.h index ef82097e2424..d2b455442f0a 100644 --- a/contrib/wpa/wpa_supplicant/gas_query.h +++ b/contrib/wpa/wpa_supplicant/gas_query.h @@ -19,6 +19,7 @@ void gas_query_deinit(struct gas_query *gas); int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, const u8 *bssid, u8 categ, const u8 *data, size_t len, int freq); +int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr); /** * enum gas_query_result - GAS query result @@ -29,16 +30,18 @@ enum gas_query_result { GAS_QUERY_TIMEOUT, GAS_QUERY_PEER_ERROR, GAS_QUERY_INTERNAL_ERROR, + GAS_QUERY_STOPPED, GAS_QUERY_DELETED_AT_DEINIT }; int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, - struct wpabuf *req, + int wildcard_bssid, struct wpabuf *req, void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code), void *ctx); +int gas_query_stop(struct gas_query *gas, u8 dialog_token); #else /* CONFIG_GAS */ diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.c b/contrib/wpa/wpa_supplicant/hs20_supplicant.c index e88f147bbd1b..cb236df18d86 100644 --- a/contrib/wpa/wpa_supplicant/hs20_supplicant.c +++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.c @@ -49,9 +49,12 @@ struct osu_provider { u8 bssid[ETH_ALEN]; u8 osu_ssid[SSID_MAX_LEN]; u8 osu_ssid_len; + u8 osu_ssid2[SSID_MAX_LEN]; + u8 osu_ssid2_len; char server_uri[256]; u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */ char osu_nai[256]; + char osu_nai2[256]; struct osu_lang_string friendly_name[OSU_MAX_ITEMS]; size_t friendly_name_count; struct osu_lang_string serv_desc[OSU_MAX_ITEMS]; @@ -92,8 +95,7 @@ void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s) return; } - /* Check if Proxy ARP is enabled (2nd byte in the IE) */ - if (ext_capa[3] & BIT(4)) + if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP)) filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP | WPA_DATA_FRAME_FILTER_FLAG_NA; @@ -101,15 +103,22 @@ void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s) } -void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id) +void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, int ap_release) { + int release; u8 conf; + release = (HS20_VERSION >> 4) + 1; + if (ap_release > 0 && release > ap_release) + release = ap_release; + if (release < 2) + pps_mo_id = -1; + wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE); - conf = HS20_VERSION; + conf = (release - 1) << 4; if (pps_mo_id >= 0) conf |= HS20_PPS_MO_ID_PRESENT; wpabuf_put_u8(buf, conf); @@ -118,6 +127,37 @@ void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id) } +void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf, + const struct wpa_ssid *ssid) +{ + if (!ssid->roaming_consortium_selection || + !ssid->roaming_consortium_selection_len) + return; + + wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(buf, 4 + ssid->roaming_consortium_selection_len); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, HS20_ROAMING_CONS_SEL_OUI_TYPE); + wpabuf_put_data(buf, ssid->roaming_consortium_selection, + ssid->roaming_consortium_selection_len); +} + + +int get_hs20_version(struct wpa_bss *bss) +{ + const u8 *ie; + + if (!bss) + return 0; + + ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE); + if (!ie || ie[1] < 5) + return 0; + + return ((ie[6] >> 4) & 0x0f) + 1; +} + + int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { @@ -248,7 +288,7 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, if (buf == NULL) return -1; - res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); + res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); @@ -391,7 +431,7 @@ static void hs20_set_osu_access_permission(const char *osu_dir, return; } - if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) { + if (lchown(fname, statbuf.st_uid, statbuf.st_gid) < 0) { wpa_printf(MSG_WARNING, "Cannot change the ownership for %s", fname); } @@ -429,10 +469,9 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { if (icon->dialog_token == dialog_token && !icon->image && os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) { - icon->image = os_malloc(slen); + icon->image = os_memdup(pos, slen); if (!icon->image) return -1; - os_memcpy(icon->image, pos, slen); icon->image_len = slen; hs20_remove_duplicate_icons(wpa_s, icon); wpa_msg(wpa_s, MSG_INFO, @@ -646,6 +685,25 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, wpa_s, NULL); } break; + case HS20_STYPE_OPERATOR_ICON_METADATA: + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR + " Operator Icon Metadata", MAC2STR(sa)); + wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen); + if (anqp) { + wpabuf_free(anqp->hs20_operator_icon_metadata); + anqp->hs20_operator_icon_metadata = + wpabuf_alloc_copy(pos, slen); + } + break; + case HS20_STYPE_OSU_PROVIDERS_NAI_LIST: + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR + " OSU Providers NAI List", MAC2STR(sa)); + if (anqp) { + wpabuf_free(anqp->hs20_osu_providers_nai_list); + anqp->hs20_osu_providers_nai_list = + wpabuf_alloc_copy(pos, slen); + } + break; default: wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); break; @@ -725,8 +783,15 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s) wpa_ssid_txt(osu->osu_ssid, osu->osu_ssid_len)); } + if (osu->osu_ssid2_len) { + fprintf(f, "osu_ssid2=%s\n", + wpa_ssid_txt(osu->osu_ssid2, + osu->osu_ssid2_len)); + } if (osu->osu_nai[0]) fprintf(f, "osu_nai=%s\n", osu->osu_nai); + if (osu->osu_nai2[0]) + fprintf(f, "osu_nai2=%s\n", osu->osu_nai2); for (j = 0; j < osu->friendly_name_count; j++) { fprintf(f, "friendly_name=%s:%s\n", osu->friendly_name[j].lang, @@ -790,6 +855,7 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s) static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *osu_ssid, u8 osu_ssid_len, + const u8 *osu_ssid2, u8 osu_ssid2_len, const u8 *pos, size_t len) { struct osu_provider *prov; @@ -811,6 +877,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, os_memcpy(prov->bssid, bss->bssid, ETH_ALEN); os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len); prov->osu_ssid_len = osu_ssid_len; + if (osu_ssid2) + os_memcpy(prov->osu_ssid2, osu_ssid2, osu_ssid2_len); + prov->osu_ssid2_len = osu_ssid2_len; /* OSU Friendly Name Length */ if (end - pos < 2) { @@ -992,18 +1061,30 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) struct wpabuf *prov_anqp; const u8 *pos, *end; u16 len; - const u8 *osu_ssid; - u8 osu_ssid_len; + const u8 *osu_ssid, *osu_ssid2; + u8 osu_ssid_len, osu_ssid2_len; u8 num_providers; hs20_free_osu_prov(wpa_s); dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + struct wpa_ie_data data; + const u8 *ie; + if (bss->anqp == NULL) continue; prov_anqp = bss->anqp->hs20_osu_providers_list; if (prov_anqp == NULL) continue; + ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &data) == 0 && + (data.key_mgmt & WPA_KEY_MGMT_OSEN)) { + osu_ssid2 = bss->ssid; + osu_ssid2_len = bss->ssid_len; + } else { + osu_ssid2 = NULL; + osu_ssid2_len = 0; + } wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from " MACSTR, MAC2STR(bss->bssid)); wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list", @@ -1045,7 +1126,8 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) if (len > (unsigned int) (end - pos)) break; hs20_osu_add_prov(wpa_s, bss, osu_ssid, - osu_ssid_len, pos, len); + osu_ssid_len, osu_ssid2, + osu_ssid2_len, pos, len); pos += len; } @@ -1054,6 +1136,35 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) "extra data after OSU Providers", (int) (end - pos)); } + + prov_anqp = bss->anqp->hs20_osu_providers_nai_list; + if (!prov_anqp) + continue; + wpa_printf(MSG_DEBUG, + "HS 2.0: Parsing OSU Providers NAI List from " + MACSTR, MAC2STR(bss->bssid)); + wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List", + prov_anqp); + pos = wpabuf_head(prov_anqp); + end = pos + wpabuf_len(prov_anqp); + num_providers = 0; + while (end - pos > 0) { + len = *pos++; + if (end - pos < len) { + wpa_printf(MSG_DEBUG, + "HS 2.0: Not enough room for OSU_NAI"); + break; + } + if (num_providers >= wpa_s->osu_prov_count) { + wpa_printf(MSG_DEBUG, + "HS 2.0: Ignore unexpected OSU Provider NAI List entries"); + break; + } + os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2, + pos, len); + pos += len; + num_providers++; + } } wpa_s->fetch_osu_icon_in_progress = 1; @@ -1207,6 +1318,18 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, } +void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url) +{ + if (!wpa_sm_pmf_enabled(wpa_s->wpa)) { + wpa_printf(MSG_DEBUG, + "HS 2.0: Ignore Terms and Conditions Acceptance since PMF was not enabled"); + return; + } + + wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url); +} + + void hs20_init(struct wpa_supplicant *wpa_s) { dl_list_init(&wpa_s->icon_head); diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.h b/contrib/wpa/wpa_supplicant/hs20_supplicant.h index 0dd559fdbf01..e43414bc65c5 100644 --- a/contrib/wpa/wpa_supplicant/hs20_supplicant.h +++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.h @@ -9,7 +9,10 @@ #define HS20_SUPPLICANT_H void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s); -void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id); +void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, + int ap_release); +void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf, + const struct wpa_ssid *ssid); int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, const u8 *payload, size_t payload_len, int inmem); @@ -18,6 +21,7 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, const u8 *data, size_t slen, u8 dialog_token); +int get_hs20_version(struct wpa_bss *bss); int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss); int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -27,6 +31,7 @@ void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s, const char *url, u8 osu_method); void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url); +void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url); void hs20_free_osu_prov(struct wpa_supplicant *wpa_s); void hs20_next_osu_icon(struct wpa_supplicant *wpa_s); diff --git a/contrib/wpa/wpa_supplicant/ibss_rsn.c b/contrib/wpa/wpa_supplicant/ibss_rsn.c index 53d7d57bde35..e96ea65a7887 100644 --- a/contrib/wpa/wpa_supplicant/ibss_rsn.c +++ b/contrib/wpa/wpa_supplicant/ibss_rsn.c @@ -259,9 +259,15 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level, static const u8 * auth_get_psk(void *ctx, const u8 *addr, - const u8 *p2p_dev_addr, const u8 *prev_psk) + const u8 *p2p_dev_addr, const u8 *prev_psk, + size_t *psk_len, int *vlan_id) { struct ibss_rsn *ibss_rsn = ctx; + + if (psk_len) + *psk_len = PMK_LEN; + if (vlan_id) + *vlan_id = 0; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk); if (prev_psk) @@ -408,7 +414,15 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, const u8 *own_addr, struct wpa_ssid *ssid) { struct wpa_auth_config conf; - struct wpa_auth_callbacks cb; + static const struct wpa_auth_callbacks cb = { + .logger = auth_logger, + .set_eapol = auth_set_eapol, + .send_eapol = auth_send_eapol, + .get_psk = auth_get_psk, + .set_key = auth_set_key, + .for_each_sta = auth_for_each_sta, + .disconnect = ibss_rsn_disconnect, + }; wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); @@ -420,18 +434,10 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, conf.wpa_group = WPA_CIPHER_CCMP; conf.eapol_version = 2; conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600; + conf.wpa_group_update_count = 4; + conf.wpa_pairwise_update_count = 4; - os_memset(&cb, 0, sizeof(cb)); - cb.ctx = ibss_rsn; - cb.logger = auth_logger; - cb.set_eapol = auth_set_eapol; - cb.send_eapol = auth_send_eapol; - cb.get_psk = auth_get_psk; - cb.set_key = auth_set_key; - cb.for_each_sta = auth_for_each_sta; - cb.disconnect = ibss_rsn_disconnect; - - ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); + ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb, ibss_rsn); if (ibss_rsn->auth_group == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); return -1; @@ -453,12 +459,12 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, } /* TODO: get peer RSN IE with Probe Request */ - if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, + if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, 0, (u8 *) "\x30\x14\x01\x00" "\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x02" - "\x00\x00", 22, NULL, 0) != + "\x00\x00", 22, NULL, 0, NULL, 0) != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); return -1; @@ -760,10 +766,9 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, if (supp < 0) return -1; - tmp = os_malloc(len); + tmp = os_memdup(buf, len); if (tmp == NULL) return -1; - os_memcpy(tmp, buf, len); if (supp) { peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER; wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from " @@ -838,6 +843,18 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, MAC2STR(addr)); if (peer && + peer->authentication_status & (IBSS_RSN_SET_PTK_SUPP | + IBSS_RSN_SET_PTK_AUTH)) { + /* Clear the TK for this pair to allow recovery from the case + * where the peer STA has restarted and lost its key while we + * still have a pairwise key configured. */ + 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); + } + + if (peer && peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { if (peer->own_auth_tx.sec) { struct os_reltime now, diff; diff --git a/contrib/wpa/wpa_supplicant/interworking.c b/contrib/wpa/wpa_supplicant/interworking.c index 1fb40c74e5cf..f94cd1614c60 100644 --- a/contrib/wpa/wpa_supplicant/interworking.c +++ b/contrib/wpa/wpa_supplicant/interworking.c @@ -106,10 +106,12 @@ static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, if (buf == NULL) return NULL; - len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); - for (i = 0; i < num_ids; i++) - wpabuf_put_le16(buf, info_ids[i]); - gas_anqp_set_element_len(buf, len_pos); + if (num_ids > 0) { + len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); + for (i = 0; i < num_ids; i++) + wpabuf_put_le16(buf, info_ids[i]); + gas_anqp_set_element_len(buf, len_pos); + } if (extra) wpabuf_put_buf(buf, extra); @@ -146,6 +148,8 @@ static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) return 1; if (cred->required_roaming_consortium_len) return 1; + if (cred->num_roaming_consortiums) + return 1; } return 0; } @@ -299,8 +303,10 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY); if (all) wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS); - if (all) + if (all) { wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST); + wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST); + } gas_anqp_set_element_len(extra, len_pos); } #endif /* CONFIG_HS20 */ @@ -310,7 +316,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, if (buf == NULL) return -1; - res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf, + res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf, interworking_anqp_resp_cb, wpa_s); if (res < 0) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request"); @@ -952,6 +958,7 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP"; if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 || wpa_config_set(ssid, "proto", "RSN", 0) < 0 || + wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 || wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) return -1; return 0; @@ -1143,6 +1150,23 @@ static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, } +static int cred_roaming_consortiums_match(const u8 *ie, + const struct wpabuf *anqp, + const struct wpa_cred *cred) +{ + unsigned int i; + + for (i = 0; i < cred->num_roaming_consortiums; i++) { + if (roaming_consortium_match(ie, anqp, + cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) + return 1; + } + + return 0; +} + + static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) { const u8 *ie; @@ -1347,27 +1371,28 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium( { struct wpa_cred *cred, *selected = NULL; const u8 *ie; + const struct wpabuf *anqp; int is_excluded = 0; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); + anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL; - if (ie == NULL && - (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) + if (!ie && !anqp) return NULL; if (wpa_s->conf->cred == NULL) return NULL; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { - if (cred->roaming_consortium_len == 0) + if (cred->roaming_consortium_len == 0 && + cred->num_roaming_consortiums == 0) continue; - if (!roaming_consortium_match(ie, - bss->anqp ? - bss->anqp->roaming_consortium : - NULL, - cred->roaming_consortium, - cred->roaming_consortium_len)) + if ((cred->roaming_consortium_len == 0 || + !roaming_consortium_match(ie, anqp, + cred->roaming_consortium, + cred->roaming_consortium_len)) && + !cred_roaming_consortiums_match(ie, anqp, cred)) continue; if (cred_no_required_oi_match(cred, bss)) @@ -1533,6 +1558,9 @@ static int interworking_connect_roaming_consortium( struct wpa_bss *bss, int only_add) { struct wpa_ssid *ssid; + const u8 *ie; + const struct wpabuf *anqp; + unsigned int i; wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR " based on roaming consortium match", MAC2STR(bss->bssid)); @@ -1562,6 +1590,26 @@ static int interworking_connect_roaming_consortium( if (interworking_set_hs20_params(wpa_s, ssid) < 0) goto fail; + ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); + anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL; + for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) { + if (!roaming_consortium_match( + ie, anqp, cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) + continue; + + ssid->roaming_consortium_selection = + os_malloc(cred->roaming_consortiums_len[i]); + if (!ssid->roaming_consortium_selection) + goto fail; + os_memcpy(ssid->roaming_consortium_selection, + cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i]); + ssid->roaming_consortium_selection_len = + cred->roaming_consortiums_len[i]; + break; + } + if (cred->eap_method == NULL) { wpa_msg(wpa_s, MSG_DEBUG, "Interworking: No EAP method set for credential using roaming consortium"); @@ -1769,9 +1817,10 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, switch (eap->method) { case EAP_TYPE_TTLS: if (eap->inner_method) { - os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", - eap_get_name(EAP_VENDOR_IETF, - eap->inner_method)); + name = eap_get_name(EAP_VENDOR_IETF, eap->inner_method); + if (!name) + goto fail; + os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", name); if (wpa_config_set(ssid, "phase2", buf, 0) < 0) goto fail; break; @@ -1894,7 +1943,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp( size_t len; wpa_msg(wpa_s, MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy"); - wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, + wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1, wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { @@ -2530,7 +2579,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, MAC2STR(selected->bssid)); interworking_connect(wpa_s, selected, 0); - } + } else if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); } @@ -2576,7 +2626,6 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; int found = 0; - const u8 *ie; wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - " "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d", @@ -2599,8 +2648,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!(bss->caps & IEEE80211_CAP_ESS)) continue; - ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); - if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80)) + if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_INTERWORKING)) continue; /* AP does not support Interworking */ if (disallowed_bssid(wpa_s, bss->bssid) || disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) @@ -2693,7 +2741,7 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u16 info_ids[], size_t num_ids, u32 subtypes, - int get_cell_pref) + u32 mbo_subtypes) { struct wpabuf *buf; struct wpabuf *extra_buf = NULL; @@ -2727,13 +2775,14 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, #endif /* CONFIG_HS20 */ #ifdef CONFIG_MBO - if (get_cell_pref) { + if (mbo_subtypes) { struct wpabuf *mbo; - mbo = mbo_build_anqp_buf(wpa_s, bss); + mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes); if (mbo) { if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) { wpabuf_free(extra_buf); + wpabuf_free(mbo); return -1; } wpabuf_put_buf(extra_buf, mbo); @@ -2747,7 +2796,7 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, if (buf == NULL) return -1; - res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); + res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); @@ -2796,6 +2845,31 @@ static void anqp_add_extra(struct wpa_supplicant *wpa_s, } +static void interworking_parse_venue_url(struct wpa_supplicant *wpa_s, + const u8 *data, size_t len) +{ + const u8 *pos = data, *end = data + len; + char url[255]; + + while (end - pos >= 2) { + u8 slen, num; + + slen = *pos++; + if (slen < 1 || slen > end - pos) { + wpa_printf(MSG_DEBUG, + "ANQP: Truncated Venue URL Duple field"); + return; + } + + num = *pos++; + os_memcpy(url, pos, slen - 1); + url[slen - 1] = '\0'; + wpa_msg(wpa_s, MSG_INFO, RX_VENUE_URL "%u %s", num, url); + pos += slen - 1; + } +} + + static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, @@ -2804,9 +2878,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; -#ifdef CONFIG_HS20 u8 type; -#endif /* CONFIG_HS20 */ if (bss) anqp = bss->anqp; @@ -2892,12 +2964,35 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, anqp->domain_name = wpabuf_alloc_copy(pos, slen); } break; +#ifdef CONFIG_FILS + case ANQP_FILS_REALM_INFO: + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR + " FILS Realm Information", MAC2STR(sa)); + wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information", + pos, slen); + if (anqp) { + wpabuf_free(anqp->fils_realm_info); + anqp->fils_realm_info = wpabuf_alloc_copy(pos, slen); + } + break; +#endif /* CONFIG_FILS */ + case ANQP_VENUE_URL: + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL", + MAC2STR(sa)); + anqp_add_extra(wpa_s, anqp, info_id, pos, slen); + + if (!pmf_in_use(wpa_s, sa)) { + wpa_printf(MSG_DEBUG, + "ANQP: Ignore Venue URL since PMF was not enabled"); + break; + } + interworking_parse_venue_url(wpa_s, pos, slen); + break; case ANQP_VENDOR_SPECIFIC: if (slen < 3) return; switch (WPA_GET_BE24(pos)) { -#ifdef CONFIG_HS20 case OUI_WFA: pos += 3; slen -= 3; @@ -2908,19 +3003,26 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, slen--; switch (type) { +#ifdef CONFIG_HS20 case HS20_ANQP_OUI_TYPE: hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa, pos, slen, dialog_token); break; +#endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + case MBO_ANQP_OUI_TYPE: + mbo_parse_rx_anqp_resp(wpa_s, bss, sa, + pos, slen); + break; +#endif /* CONFIG_MBO */ default: wpa_msg(wpa_s, MSG_DEBUG, - "HS20: Unsupported ANQP vendor type %u", + "ANQP: Unsupported ANQP vendor type %u", type); break; } break; -#endif /* CONFIG_HS20 */ default: wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Unsupported vendor-specific ANQP OUI %06x", @@ -3133,7 +3235,7 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, } else wpabuf_put_le16(buf, 0); - res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s); + res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s); if (res < 0) { wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request"); wpabuf_free(buf); diff --git a/contrib/wpa/wpa_supplicant/interworking.h b/contrib/wpa/wpa_supplicant/interworking.h index 3d22292618b2..37ee2e904e48 100644 --- a/contrib/wpa/wpa_supplicant/interworking.h +++ b/contrib/wpa/wpa_supplicant/interworking.h @@ -13,7 +13,7 @@ enum gas_query_result; int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u16 info_ids[], size_t num_ids, u32 subtypes, - int get_cell_pref); + u32 mbo_subtypes); void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, diff --git a/contrib/wpa/wpa_supplicant/main.c b/contrib/wpa/wpa_supplicant/main.c index e08c2fd266f1..51a8a0298a9b 100644 --- a/contrib/wpa/wpa_supplicant/main.c +++ b/contrib/wpa/wpa_supplicant/main.c @@ -28,9 +28,9 @@ static void usage(void) "s" #endif /* CONFIG_DEBUG_SYSLOG */ "t" -#ifdef CONFIG_DBUS +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW "u" -#endif /* CONFIG_DBUS */ +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ "vW] [-P<pid file>] " "[-g<global ctrl>] \\\n" " [-G<group>] \\\n" @@ -98,9 +98,9 @@ static void usage(void) " -T = record to Linux tracing in addition to logging\n" " (records all messages regardless of debug verbosity)\n" #endif /* CONFIG_DEBUG_LINUX_TRACING */ -#ifdef CONFIG_DBUS +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW " -u = enable DBus control interface\n" -#endif /* CONFIG_DBUS */ +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ " -v = show version\n" " -W = wait for a control interface monitor before starting\n"); @@ -295,11 +295,11 @@ int main(int argc, char *argv[]) case 't': params.wpa_debug_timestamp++; break; -#ifdef CONFIG_DBUS +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW case 'u': params.dbus_ctrl_interface = 1; break; -#endif /* CONFIG_DBUS */ +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ case 'v': printf("%s\n", wpa_supplicant_version); exitcode = 0; diff --git a/contrib/wpa/wpa_supplicant/mbo.c b/contrib/wpa/wpa_supplicant/mbo.c index 7e049be3df41..43b1fa7beb38 100644 --- a/contrib/wpa/wpa_supplicant/mbo.c +++ b/contrib/wpa/wpa_supplicant/mbo.c @@ -38,6 +38,32 @@ static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason) } +const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr) +{ + const u8 *mbo; + u8 ie_len = mbo_ie[1]; + + if (ie_len < MBO_IE_HEADER - 2) + return NULL; + mbo = mbo_ie + MBO_IE_HEADER; + + return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr); +} + + +const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, + enum mbo_attr_id attr) +{ + const u8 *mbo_ie; + + mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE); + if (!mbo_ie) + return NULL; + + return mbo_attr_from_mbo_ie(mbo_ie, attr); +} + + const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) { const u8 *mbo, *end; @@ -72,6 +98,13 @@ static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s, } +static void wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf *mbo, size_t size) +{ + wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT); + wpabuf_put_u8(mbo, size); /* Length */ +} + + static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s, struct wpabuf *mbo, u8 start, u8 end) { @@ -80,9 +113,7 @@ static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s, if (size + 2 > wpabuf_tailroom(mbo)) return; - wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT); - wpabuf_put_u8(mbo, size); /* Length */ - + wpas_mbo_non_pref_chan_attr_hdr(mbo, size); wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end); } @@ -119,6 +150,8 @@ static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s, if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) { if (subelement) wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4); + else + wpas_mbo_non_pref_chan_attr_hdr(mbo, 0); return; } start_pref = &wpa_s->non_pref_chan[0]; @@ -149,12 +182,14 @@ static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s, } -int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len, + int add_oce_capa) { struct wpabuf *mbo; int res; - if (len < MBO_IE_HEADER + 3 + 7) + if (len < MBO_IE_HEADER + 3 + 7 + + ((wpa_s->enable_oce & OCE_STA) ? 3 : 0)) return 0; /* Leave room for the MBO IE header */ @@ -173,9 +208,16 @@ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) wpabuf_put_u8(mbo, 1); wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa); + /* Add OCE capability indication attribute if OCE is enabled */ + if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) { + wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND); + wpabuf_put_u8(mbo, 1); + wpabuf_put_u8(mbo, OCE_RELEASE); + } + res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo)); if (!res) - wpa_printf(MSG_ERROR, "Failed to add MBO IE"); + wpa_printf(MSG_ERROR, "Failed to add MBO/OCE IE"); wpabuf_free(mbo); return res; @@ -233,6 +275,7 @@ static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s) wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1); wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf), wpabuf_len(buf)); + wpas_update_mbo_connect_params(wpa_s); wpabuf_free(buf); } @@ -258,10 +301,10 @@ static int wpa_non_pref_chan_cmp(const void *_a, const void *_b) const struct wpa_mbo_non_pref_channel *a = _a, *b = _b; if (a->oper_class != b->oper_class) - return a->oper_class - b->oper_class; + return (int) a->oper_class - (int) b->oper_class; if (a->reason != b->reason) - return a->reason - b->reason; - return a->preference - b->preference; + return (int) a->reason - (int) b->reason; + return (int) a->preference - (int) b->preference; } @@ -277,11 +320,10 @@ int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, non_pref_chan ? non_pref_chan : "N/A"); /* - * The shortest channel configuration is 10 characters - commas, 3 - * colons, and 4 values that one of them (oper_class) is 2 digits or - * more. + * The shortest channel configuration is 7 characters - 3 colons and + * 4 values. */ - if (!non_pref_chan || os_strlen(non_pref_chan) < 10) + if (!non_pref_chan || os_strlen(non_pref_chan) < 7) goto update; cmd = os_strdup(non_pref_chan); @@ -369,315 +411,30 @@ fail: void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie) { + u8 *len; + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); - wpabuf_put_u8(ie, 7); + len = wpabuf_put(ie, 1); + wpabuf_put_be24(ie, OUI_WFA); wpabuf_put_u8(ie, MBO_OUI_TYPE); wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA); wpabuf_put_u8(ie, 1); wpabuf_put_u8(ie, wpa_s->conf->mbo_cell_capa); -} - - -enum chan_allowed { - NOT_ALLOWED, ALLOWED -}; - -static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan, - unsigned int *flags) -{ - int i; - - for (i = 0; i < mode->num_channels; i++) { - if (mode->channels[i].chan == chan) - break; + if (wpa_s->enable_oce & OCE_STA) { + wpabuf_put_u8(ie, OCE_ATTR_ID_CAPA_IND); + wpabuf_put_u8(ie, 1); + wpabuf_put_u8(ie, OCE_RELEASE); } - - if (i == mode->num_channels || - (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)) - return NOT_ALLOWED; - - if (flags) - *flags = mode->channels[i].flag; - - return ALLOWED; -} - - -static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel) -{ - u8 center_channels[] = {42, 58, 106, 122, 138, 155}; - size_t i; - - if (mode->mode != HOSTAPD_MODE_IEEE80211A) - return 0; - - for (i = 0; i < ARRAY_SIZE(center_channels); i++) { - /* - * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48), - * so the center channel is 6 channels away from the start/end. - */ - if (channel >= center_channels[i] - 6 && - channel <= center_channels[i] + 6) - return center_channels[i]; - } - - return 0; -} - - -static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel) -{ - u8 center_chan; - unsigned int i; - - center_chan = get_center_80mhz(mode, channel); - if (!center_chan) - return NOT_ALLOWED; - - /* check all the channels are available */ - for (i = 0; i < 4; i++) { - unsigned int flags; - u8 adj_chan = center_chan - 6 + i * 4; - - if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED) - return NOT_ALLOWED; - - if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) || - (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) || - (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) || - (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))) - return NOT_ALLOWED; - } - - return ALLOWED; -} - - -static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel) -{ - u8 center_channels[] = { 50, 114 }; - unsigned int i; - - if (mode->mode != HOSTAPD_MODE_IEEE80211A) - return 0; - - for (i = 0; i < ARRAY_SIZE(center_channels); i++) { - /* - * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64), - * so the center channel is 14 channels away from the start/end. - */ - if (channel >= center_channels[i] - 14 && - channel <= center_channels[i] + 14) - return center_channels[i]; - } - - return 0; -} - - -static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, - u8 channel) -{ - u8 center_chan; - unsigned int i; - - center_chan = get_center_160mhz(mode, channel); - if (!center_chan) - return NOT_ALLOWED; - - /* Check all the channels are available */ - for (i = 0; i < 8; i++) { - unsigned int flags; - u8 adj_chan = center_chan - 14 + i * 4; - - if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED) - return NOT_ALLOWED; - - if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) || - (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) || - (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) || - (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) || - (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) || - (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) || - (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) || - (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))) - return NOT_ALLOWED; - } - - return ALLOWED; -} - - -static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, - u8 channel, u8 bw) -{ - unsigned int flag = 0; - enum chan_allowed res, res2; - - res2 = res = allow_channel(mode, channel, &flag); - if (bw == BW40MINUS) { - if (!(flag & HOSTAPD_CHAN_HT40MINUS)) - return NOT_ALLOWED; - res2 = allow_channel(mode, channel - 4, NULL); - } else if (bw == BW40PLUS) { - if (!(flag & HOSTAPD_CHAN_HT40PLUS)) - return NOT_ALLOWED; - res2 = allow_channel(mode, 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); - } 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); - } 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); - } - - if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) - return NOT_ALLOWED; - - return ALLOWED; -} - - -static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, - const struct oper_class_map *op_class) -{ - int chan; - size_t i; - struct hostapd_hw_modes *mode; - int found; - - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode); - if (!mode) - return 0; - - if (op_class->op_class == 128) { - 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) == - ALLOWED) - return 1; - } - - return 0; - } - - if (op_class->op_class == 129) { - /* Check if either 160 MHz channels is allowed */ - return verify_channel(mode, 50, op_class->bw) == ALLOWED || - verify_channel(mode, 114, op_class->bw) == 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) == ALLOWED || - verify_channel(mode, 58, op_class->bw) == ALLOWED) - found++; - if (verify_channel(mode, 106, op_class->bw) == ALLOWED || - verify_channel(mode, 122, op_class->bw) == ALLOWED || - verify_channel(mode, 138, op_class->bw) == ALLOWED) - found++; - if (verify_channel(mode, 106, op_class->bw) == ALLOWED && - verify_channel(mode, 138, op_class->bw) == ALLOWED) - found++; - if (verify_channel(mode, 155, op_class->bw) == ALLOWED) - found++; - - if (found >= 2) - return 1; - - return 0; - } - - 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) == ALLOWED) { - found = 1; - break; - } - } - - return found; -} - - -int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos, - size_t len) -{ - struct wpabuf *buf; - u8 op, current, chan; - u8 *ie_len; - int res; - - /* - * Assume 20 MHz channel for now. - * TODO: Use the secondary channel and VHT channel width that will be - * used after association. - */ - if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT, - ¤t, &chan) == NUM_HOSTAPD_MODES) - return 0; - - /* - * Need 3 bytes for EID, length, and current operating class, plus - * 1 byte for every other supported operating class. - */ - buf = wpabuf_alloc(global_op_class_size + 3); - if (!buf) - return 0; - - wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES); - /* Will set the length later, putting a placeholder */ - ie_len = wpabuf_put(buf, 1); - wpabuf_put_u8(buf, current); - - for (op = 0; global_op_class[op].op_class; op++) { - if (wpas_op_class_supported(wpa_s, &global_op_class[op])) - wpabuf_put_u8(buf, global_op_class[op].op_class); - } - - *ie_len = wpabuf_len(buf) - 2; - if (*ie_len < 2 || wpabuf_len(buf) > len) { - wpa_printf(MSG_ERROR, - "Failed to add supported operating classes IE"); - res = 0; - } else { - os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf)); - res = wpabuf_len(buf); - wpa_hexdump_buf(MSG_DEBUG, - "MBO: Added supported operating classes IE", - buf); - } - - wpabuf_free(buf); - return res; + *len = (u8 *) wpabuf_put(ie, 0) - len - 1; } void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie, size_t len) { - const u8 *pos, *cell_pref = NULL, *reason = NULL; + const u8 *pos, *cell_pref = NULL; u8 id, elen; u16 disallowed_sec = 0; @@ -712,7 +469,8 @@ void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie, if (elen != 1) goto fail; - reason = pos; + wpa_s->wnm_mbo_trans_reason_present = 1; + wpa_s->wnm_mbo_transition_reason = *pos; break; case MBO_ATTR_ID_ASSOC_RETRY_DELAY: if (elen != 2) @@ -726,6 +484,9 @@ void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie, } else if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { disallowed_sec = WPA_GET_LE16(pos); + wpa_printf(MSG_DEBUG, + "MBO: Association retry delay: %u", + disallowed_sec); } else { wpa_printf(MSG_DEBUG, "MBO: Association retry delay attribute not in disassoc imminent mode"); @@ -755,13 +516,13 @@ void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie, wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u", *cell_pref); - if (reason) + if (wpa_s->wnm_mbo_trans_reason_present) wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u", - *reason); + wpa_s->wnm_mbo_transition_reason); if (disallowed_sec && wpa_s->current_bss) wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid, - disallowed_sec); + disallowed_sec, 0); return; fail: @@ -805,14 +566,16 @@ void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa) wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7); wpa_supplicant_set_default_scan_ies(wpa_s); + wpas_update_mbo_connect_params(wpa_s); } struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss) + struct wpa_bss *bss, u32 mbo_subtypes) { struct wpabuf *anqp_buf; u8 *len_pos; + u8 i; if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) { wpa_printf(MSG_INFO, "MBO: " MACSTR @@ -821,7 +584,8 @@ struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, return NULL; } - anqp_buf = wpabuf_alloc(10); + /* Allocate size for the maximum case - all MBO subtypes are set */ + anqp_buf = wpabuf_alloc(9 + MAX_MBO_ANQP_SUBTYPE); if (!anqp_buf) return NULL; @@ -829,8 +593,43 @@ struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, wpabuf_put_be24(anqp_buf, OUI_WFA); wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE); - wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF); + wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_QUERY_LIST); + + /* The first valid MBO subtype is 1 */ + for (i = 1; i <= MAX_MBO_ANQP_SUBTYPE; i++) { + if (mbo_subtypes & BIT(i)) + wpabuf_put_u8(anqp_buf, i); + } + gas_anqp_set_element_len(anqp_buf, len_pos); return anqp_buf; } + + +void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, const u8 *sa, + const u8 *data, size_t slen) +{ + const u8 *pos = data; + u8 subtype; + + if (slen < 1) + return; + + subtype = *pos++; + slen--; + + switch (subtype) { + case MBO_ANQP_SUBTYPE_CELL_CONN_PREF: + if (slen < 1) + break; + wpa_msg(wpa_s, MSG_INFO, RX_MBO_ANQP MACSTR + " cell_conn_pref=%u", MAC2STR(sa), *pos); + break; + default: + wpa_printf(MSG_DEBUG, "MBO: Unsupported ANQP subtype %u", + subtype); + break; + } +} diff --git a/contrib/wpa/wpa_supplicant/mesh.c b/contrib/wpa/wpa_supplicant/mesh.c index d67d3b2aa390..92600211ac2d 100644 --- a/contrib/wpa/wpa_supplicant/mesh.c +++ b/contrib/wpa/wpa_supplicant/mesh.c @@ -34,6 +34,8 @@ static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s) wpa_s->current_ssid = NULL; os_free(wpa_s->mesh_rsn); wpa_s->mesh_rsn = NULL; + os_free(wpa_s->mesh_params); + wpa_s->mesh_params = NULL; /* TODO: leave mesh (stop beacon). This will happen on link down * anyway, so it's not urgent */ } @@ -84,6 +86,7 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s, 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) @@ -91,6 +94,10 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s, else conf->ieee80211w = NO_MGMT_FRAME_PROTECTION; } +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + conf->ocv = ssid->ocv; +#endif /* CONFIG_OCV */ cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0); if (cipher < 0 || cipher == WPA_CIPHER_TKIP) { @@ -145,17 +152,104 @@ static void wpas_mesh_copy_groups(struct hostapd_data *bss, } +static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s) +{ + struct hostapd_iface *ifmsh = wpa_s->ifmsh; + struct wpa_ssid *ssid = wpa_s->current_ssid; + struct hostapd_data *bss = ifmsh->bss[0]; + static int default_groups[] = { 19, 20, 21, 25, 26, -1 }; + const char *password; + size_t len; + + password = ssid->sae_password; + if (!password) + password = ssid->passphrase; + if (!password) { + wpa_printf(MSG_ERROR, + "mesh: Passphrase for SAE not configured"); + return -1; + } + + bss->conf->wpa = ssid->proto; + bss->conf->wpa_key_mgmt = ssid->key_mgmt; + + if (wpa_s->conf->sae_groups && wpa_s->conf->sae_groups[0] > 0) { + wpas_mesh_copy_groups(bss, wpa_s); + } else { + bss->conf->sae_groups = os_memdup(default_groups, + sizeof(default_groups)); + if (!bss->conf->sae_groups) + return -1; + } + + len = os_strlen(password); + bss->conf->ssid.wpa_passphrase = dup_binstr(password, len); + + wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf); + return !wpa_s->mesh_rsn ? -1 : 0; +} + + +static int wpas_mesh_complete(struct wpa_supplicant *wpa_s) +{ + struct hostapd_iface *ifmsh = wpa_s->ifmsh; + struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params; + struct wpa_ssid *ssid = wpa_s->current_ssid; + int ret; + + if (!params || !ssid || !ifmsh) { + wpa_printf(MSG_ERROR, "mesh: %s called without active mesh", + __func__); + return -1; + } + + if (ifmsh->mconf->security != MESH_CONF_SEC_NONE && + wpas_mesh_init_rsn(wpa_s)) { + wpa_printf(MSG_ERROR, + "mesh: RSN initialization failed - deinit mesh"); + wpa_supplicant_mesh_deinit(wpa_s); + return -1; + } + + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher; + wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher; + wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher; + } + + params->ies = ifmsh->mconf->rsn_ie; + params->ie_len = ifmsh->mconf->rsn_ie_len; + params->basic_rates = ifmsh->basic_rates; + params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE; + params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode; + + wpa_msg(wpa_s, MSG_INFO, "joining mesh %s", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + ret = wpa_drv_join_mesh(wpa_s, params); + if (ret) + wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret); + + /* hostapd sets the interface down until we associate */ + wpa_drv_set_operstate(wpa_s, 1); + + if (!ret) + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + + return ret; +} + + static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid) + struct wpa_ssid *ssid, + struct hostapd_freq_params *freq) { struct hostapd_iface *ifmsh; struct hostapd_data *bss; struct hostapd_config *conf; struct mesh_conf *mconf; int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 }; - static int default_groups[] = { 19, 20, 21, 25, 26, -1 }; - size_t len; int rate_len; + int frequency; if (!wpa_s->conf->user_mpm) { /* not much for us to do here */ @@ -164,7 +258,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, return 0; } - wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh)); + wpa_s->ifmsh = ifmsh = hostapd_alloc_iface(); if (!ifmsh) return -ENOMEM; @@ -175,17 +269,23 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, if (!ifmsh->bss) goto out_free; - ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data)); + ifmsh->bss[0] = bss = hostapd_alloc_bss_data(NULL, NULL, NULL); if (!bss) goto out_free; - dl_list_init(&bss->nr_db); + ifmsh->bss[0]->msg_ctx = wpa_s; os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN); bss->driver = wpa_s->driver; bss->drv_priv = wpa_s->drv_priv; bss->iface = ifmsh; bss->mesh_sta_free_cb = mesh_mpm_free_sta; - wpa_s->assoc_freq = ssid->frequency; + frequency = ssid->frequency; + if (frequency != freq->freq && + frequency == freq->freq + freq->sec_channel_offset * 20) { + wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched"); + frequency = freq->freq; + } + wpa_s->assoc_freq = frequency; wpa_s->current_ssid = ssid; /* setup an AP config for auth processing */ @@ -197,6 +297,16 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, bss->conf->start_disabled = 1; bss->conf->mesh = MESH_ENABLED; bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity; + + if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes, + wpa_s->hw.num_modes) && wpa_s->conf->country[0]) { + conf->ieee80211h = 1; + conf->ieee80211d = 1; + conf->country[0] = wpa_s->conf->country[0]; + conf->country[1] = wpa_s->conf->country[1]; + conf->country[2] = ' '; + } + bss->iconf = conf; ifmsh->conf = conf; @@ -211,27 +321,28 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, ifmsh->mconf = mconf; /* need conf->hw_mode for supported rates. */ - conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel); + conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel); if (conf->hw_mode == NUM_HOSTAPD_MODES) { wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz", - ssid->frequency); + frequency); goto out_free; } if (ssid->ht40) conf->secondary_channel = ssid->ht40; if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) { - conf->vht_oper_chwidth = ssid->max_oper_chwidth; + if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH) + conf->vht_oper_chwidth = ssid->max_oper_chwidth; switch (conf->vht_oper_chwidth) { case VHT_CHANWIDTH_80MHZ: case VHT_CHANWIDTH_80P80MHZ: ieee80211_freq_to_chan( - ssid->frequency, + frequency, &conf->vht_oper_centr_freq_seg0_idx); conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2; break; case VHT_CHANWIDTH_160MHZ: ieee80211_freq_to_chan( - ssid->frequency, + frequency, &conf->vht_oper_centr_freq_seg0_idx); conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2; conf->vht_oper_centr_freq_seg0_idx += 40 / 5; @@ -250,11 +361,10 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, * advertised in beacons match the one in peering frames, sigh. */ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) { - conf->basic_rates = os_malloc(sizeof(basic_rates_erp)); + conf->basic_rates = os_memdup(basic_rates_erp, + sizeof(basic_rates_erp)); if (!conf->basic_rates) goto out_free; - os_memcpy(conf->basic_rates, basic_rates_erp, - sizeof(basic_rates_erp)); } } else { rate_len = 0; @@ -271,46 +381,15 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, conf->basic_rates[rate_len] = -1; } - if (hostapd_setup_interface(ifmsh)) { - wpa_printf(MSG_ERROR, - "Failed to initialize hostapd interface for mesh"); - return -1; - } - if (wpa_drv_init_mesh(wpa_s)) { wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver"); return -1; } - if (mconf->security != MESH_CONF_SEC_NONE) { - if (ssid->passphrase == NULL) { - wpa_printf(MSG_ERROR, - "mesh: Passphrase for SAE not configured"); - goto out_free; - } - - bss->conf->wpa = ssid->proto; - bss->conf->wpa_key_mgmt = ssid->key_mgmt; - - if (wpa_s->conf->sae_groups && - wpa_s->conf->sae_groups[0] > 0) { - wpas_mesh_copy_groups(bss, wpa_s); - } else { - bss->conf->sae_groups = - os_malloc(sizeof(default_groups)); - if (!bss->conf->sae_groups) - goto out_free; - os_memcpy(bss->conf->sae_groups, default_groups, - sizeof(default_groups)); - } - - len = os_strlen(ssid->passphrase); - bss->conf->ssid.wpa_passphrase = - dup_binstr(ssid->passphrase, len); - - wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf); - if (!wpa_s->mesh_rsn) - goto out_free; + if (hostapd_setup_interface(ifmsh)) { + wpa_printf(MSG_ERROR, + "Failed to initialize hostapd interface for mesh"); + return -1; } wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf); @@ -355,11 +434,13 @@ void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s, int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { - struct wpa_driver_mesh_join_params params; + struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params)); int ret = 0; - if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) { + if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency || + !params) { ret = -ENOENT; + os_free(params); goto out; } @@ -369,22 +450,23 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, wpa_s->group_cipher = WPA_CIPHER_NONE; wpa_s->mgmt_group_cipher = 0; - os_memset(¶ms, 0, sizeof(params)); - params.meshid = ssid->ssid; - params.meshid_len = ssid->ssid_len; - ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq); - wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled; - wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled; - if (params.freq.ht_enabled && params.freq.sec_channel_offset) - ssid->ht40 = params.freq.sec_channel_offset; + params->meshid = ssid->ssid; + params->meshid_len = ssid->ssid_len; + ibss_mesh_setup_freq(wpa_s, ssid, ¶ms->freq); + wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled; + wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled; + if (params->freq.ht_enabled && params->freq.sec_channel_offset) + ssid->ht40 = params->freq.sec_channel_offset; + if (wpa_s->mesh_vht_enabled) { ssid->vht = 1; - switch (params.freq.bandwidth) { + ssid->vht_center_freq1 = params->freq.center_freq1; + switch (params->freq.bandwidth) { case 80: - if (params.freq.center_freq2) { + if (params->freq.center_freq2) { ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ; ssid->vht_center_freq2 = - params.freq.center_freq2; + params->freq.center_freq2; } else { ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ; } @@ -398,63 +480,44 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, } } if (ssid->beacon_int > 0) - params.beacon_int = ssid->beacon_int; + params->beacon_int = ssid->beacon_int; else if (wpa_s->conf->beacon_int > 0) - params.beacon_int = wpa_s->conf->beacon_int; + params->beacon_int = wpa_s->conf->beacon_int; if (ssid->dtim_period > 0) - params.dtim_period = ssid->dtim_period; + params->dtim_period = ssid->dtim_period; else if (wpa_s->conf->dtim_period > 0) - params.dtim_period = wpa_s->conf->dtim_period; - params.conf.max_peer_links = wpa_s->conf->max_peer_links; + params->dtim_period = wpa_s->conf->dtim_period; + params->conf.max_peer_links = wpa_s->conf->max_peer_links; + if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) { + params->conf.rssi_threshold = ssid->mesh_rssi_threshold; + params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD; + } if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { - params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH; - params.flags |= WPA_DRIVER_MESH_FLAG_AMPE; + params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH; + params->flags |= WPA_DRIVER_MESH_FLAG_AMPE; wpa_s->conf->user_mpm = 1; } if (wpa_s->conf->user_mpm) { - params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM; - params.conf.auto_plinks = 0; + params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM; + params->conf.auto_plinks = 0; } else { - params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM; - params.conf.auto_plinks = 1; + params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM; + params->conf.auto_plinks = 1; } - params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity; + params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity; - if (wpa_supplicant_mesh_init(wpa_s, ssid)) { + os_free(wpa_s->mesh_params); + wpa_s->mesh_params = params; + if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) { wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh"); wpa_drv_leave_mesh(wpa_s); ret = -1; goto out; } - if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { - wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher; - wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher; - wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher; - } - - if (wpa_s->ifmsh) { - params.ies = wpa_s->ifmsh->mconf->rsn_ie; - params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len; - params.basic_rates = wpa_s->ifmsh->basic_rates; - params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE; - params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode; - } - - wpa_msg(wpa_s, MSG_INFO, "joining mesh %s", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - ret = wpa_drv_join_mesh(wpa_s, ¶ms); - if (ret) - wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret); - - /* hostapd sets the interface down until we associate */ - wpa_drv_set_operstate(wpa_s, 1); - - if (!ret) - wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); - + ret = wpas_mesh_complete(wpa_s); out: return ret; } diff --git a/contrib/wpa/wpa_supplicant/mesh_mpm.c b/contrib/wpa/wpa_supplicant/mesh_mpm.c index d14c7e3b2045..9d6ab8da1ebe 100644 --- a/contrib/wpa/wpa_supplicant/mesh_mpm.c +++ b/contrib/wpa/wpa_supplicant/mesh_mpm.c @@ -11,6 +11,8 @@ #include "utils/common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" +#include "common/hw_features_common.h" +#include "common/ocv.h" #include "ap/hostapd.h" #include "ap/sta_info.h" #include "ap/ieee802_11.h" @@ -19,6 +21,7 @@ #include "driver_i.h" #include "mesh_mpm.h" #include "mesh_rsn.h" +#include "notify.h" struct mesh_peer_mgmt_ie { const u8 *proto_id; /* Mesh Peering Protocol Identifier (2 octets) */ @@ -186,7 +189,7 @@ static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s, do { if (os_get_random((u8 *) &llid, sizeof(llid)) < 0) - continue; + llid = 0; /* continue */ } while (!llid || llid_in_use(wpa_s, llid)); sta->my_lid = llid; @@ -220,13 +223,14 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, if (!sta) return; - buf_len = 2 + /* capability info */ + buf_len = 2 + /* Category and Action */ + 2 + /* capability info */ 2 + /* AID */ 2 + 8 + /* supported rates */ 2 + (32 - 8) + 2 + 32 + /* mesh ID */ 2 + 7 + /* mesh config */ - 2 + 23 + /* peering management */ + 2 + 24 + /* peering management */ 2 + 96 + /* AMPE */ 2 + 16; /* MIC */ #ifdef CONFIG_IEEE80211N @@ -243,6 +247,11 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, #endif /* CONFIG_IEEE80211AC */ if (type != PLINK_CLOSE) buf_len += conf->rsn_ie_len; /* RSN IE */ +#ifdef CONFIG_OCV + /* OCI is included even when the other STA doesn't support OCV */ + if (type != PLINK_CLOSE && conf->ocv) + buf_len += OCV_OCI_EXTENDED_LEN; +#endif /* CONFIG_OCV */ buf = wpabuf_alloc(buf_len); if (!buf) @@ -354,6 +363,22 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_OCV + if (type != PLINK_CLOSE && conf->ocv) { + struct wpa_channel_info ci; + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Mesh MPM: Failed to get channel info for OCI element"); + goto fail; + } + + pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN); + if (ocv_insert_extended_oci(&ci, pos) < 0) + goto fail; + } +#endif /* CONFIG_OCV */ + if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) { wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: failed to add AMPE and MIC IE"); @@ -435,7 +460,7 @@ static void plink_timer(void *eloop_ctx, void *user_data) break; } reason = WLAN_REASON_MESH_MAX_RETRIES; - /* fall through on else */ + /* fall through */ case PLINK_CNF_RCVD: /* confirm timer */ @@ -646,6 +671,9 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, 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 && @@ -677,11 +705,23 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211N copy_sta_ht_capab(data, sta, elems->ht_capabilities); + + oper = (struct ieee80211_ht_operation *) elems->ht_operation; + if (oper && + !(oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) && + sta->ht_capabilities) { + wpa_msg(wpa_s, MSG_DEBUG, MACSTR + " does not support 40 MHz bandwidth", + MAC2STR(sta->addr)); + set_disable_ht40(sta->ht_capabilities, 1); + } + update_ht_state(data, sta); #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC copy_sta_vht_capab(data, sta, elems->vht_capabilities); + copy_sta_vht_oper(data, sta, elems->vht_operation); set_sta_vht_opmode(data, sta, elems->vht_opmode_notif); #endif /* CONFIG_IEEE80211AC */ @@ -842,6 +882,9 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, /* Send ctrl event */ wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR, MAC2STR(sta->addr)); + + /* Send D-Bus event */ + wpas_notify_mesh_peer_connected(wpa_s, sta->addr); } @@ -994,6 +1037,10 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR, MAC2STR(sta->addr)); + /* Send D-Bus event */ + wpas_notify_mesh_peer_disconnected(wpa_s, sta->addr, + reason); + hapd->num_plinks--; mesh_mpm_send_plink_action(wpa_s, sta, @@ -1135,7 +1182,7 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, */ if (!sta && action_field == PLINK_OPEN && (!(mconf->security & MESH_CONF_SEC_AMPE) || - wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa))) + wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa, NULL))) sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems); if (!sta) { @@ -1172,6 +1219,56 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, } return; } + +#ifdef CONFIG_OCV + if (action_field == PLINK_OPEN && elems.rsn_ie) { + struct wpa_state_machine *sm = sta->wpa_sm; + struct wpa_ie_data data; + + res = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, + elems.rsn_ie_len + 2, + &data); + if (res) { + wpa_printf(MSG_DEBUG, + "Failed to parse RSN IE (res=%d)", + res); + wpa_hexdump(MSG_DEBUG, "RSN IE", elems.rsn_ie, + elems.rsn_ie_len); + return; + } + + wpa_auth_set_ocv(sm, mconf->ocv && + (data.capabilities & + WPA_CAPABILITY_OCVC)); + } + + if (action_field != PLINK_CLOSE && + wpa_auth_uses_ocv(sta->wpa_sm)) { + struct wpa_channel_info ci; + int tx_chanwidth; + int tx_seg1_idx; + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_printf(MSG_WARNING, + "MPM: Failed to get channel info to validate received OCI in MPM Confirm"); + return; + } + + if (get_tx_parameters( + sta, channel_width_to_int(ci.chanwidth), + ci.seg1_idx, &tx_chanwidth, + &tx_seg1_idx) < 0) + return; + + if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, + tx_chanwidth, tx_seg1_idx) != + 0) { + wpa_printf(MSG_WARNING, "MPM: %s", + ocv_errorstr); + return; + } + } +#endif /* CONFIG_OCV */ } if (sta->plink_state == PLINK_BLOCKED) { diff --git a/contrib/wpa/wpa_supplicant/mesh_rsn.c b/contrib/wpa/wpa_supplicant/mesh_rsn.c index 27ab8cb36458..4b8d6c469173 100644 --- a/contrib/wpa/wpa_supplicant/mesh_rsn.c +++ b/contrib/wpa/wpa_supplicant/mesh_rsn.c @@ -75,12 +75,17 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level, static const u8 *auth_get_psk(void *ctx, const u8 *addr, - const u8 *p2p_dev_addr, const u8 *prev_psk) + const u8 *p2p_dev_addr, const u8 *prev_psk, + size_t *psk_len, int *vlan_id) { struct mesh_rsn *mesh_rsn = ctx; struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0]; struct sta_info *sta = ap_get_sta(hapd, addr); + if (psk_len) + *psk_len = PMK_LEN; + if (vlan_id) + *vlan_id = 0; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk); @@ -137,10 +142,15 @@ static int auth_start_ampe(void *ctx, const u8 *addr) static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, - enum mfp_options ieee80211w) + enum mfp_options ieee80211w, int ocv) { struct wpa_auth_config conf; - struct wpa_auth_callbacks cb; + static const struct wpa_auth_callbacks cb = { + .logger = auth_logger, + .get_psk = auth_get_psk, + .set_key = auth_set_key, + .start_ampe = auth_start_ampe, + }; u8 seq[6] = {}; wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); @@ -153,20 +163,18 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, conf.wpa_group = rsn->group_cipher; conf.eapol_version = 0; 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 */ - os_memset(&cb, 0, sizeof(cb)); - cb.ctx = rsn; - cb.logger = auth_logger; - cb.get_psk = auth_get_psk; - cb.set_key = auth_set_key; - cb.start_ampe = auth_start_ampe; - - rsn->auth = wpa_init(addr, &conf, &cb); + rsn->auth = wpa_init(addr, &conf, &cb, rsn); if (rsn->auth == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); return -1; @@ -224,6 +232,9 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, struct hostapd_data *bss = wpa_s->ifmsh->bss[0]; const u8 *ie; size_t ie_len; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + struct external_pmksa_cache *entry; +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ mesh_rsn = os_zalloc(sizeof(*mesh_rsn)); if (mesh_rsn == NULL) @@ -234,7 +245,7 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher; if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr, - conf->ieee80211w) < 0) { + conf->ieee80211w, conf->ocv) < 0) { mesh_rsn_deinit(mesh_rsn); os_free(mesh_rsn); return NULL; @@ -242,6 +253,22 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, bss->wpa_auth = mesh_rsn->auth; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache, + struct external_pmksa_cache, + list)) != NULL) { + int ret; + + ret = wpa_auth_pmksa_add_entry(bss->wpa_auth, + entry->pmksa_cache); + dl_list_del(&entry->list); + os_free(entry); + + if (ret < 0) + return NULL; + } +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len); conf->rsn_ie = (u8 *) ie; conf->rsn_ie_len = ie_len; @@ -295,7 +322,12 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct sta_info *sta) { - if (ssid->passphrase == NULL) { + const char *password; + + password = ssid->sae_password; + if (!password) + password = ssid->passphrase; + if (!password) { wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available"); return -1; } @@ -305,9 +337,15 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s, return -1; } + if (sta->sae->tmp && !sta->sae->tmp->pw_id && ssid->sae_password_id) { + sta->sae->tmp->pw_id = os_strdup(ssid->sae_password_id); + if (!sta->sae->tmp->pw_id) + return -1; + } return sae_prepare_commit(wpa_s->own_addr, sta->addr, - (u8 *) ssid->passphrase, - os_strlen(ssid->passphrase), sta->sae); + (u8 *) password, os_strlen(password), + ssid->sae_password_id, + sta->sae); } @@ -333,7 +371,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, return -1; } - pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr); + pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL); if (pmksa) { if (!sta->wpa_sm) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, @@ -579,7 +617,7 @@ skip_keys: /* encrypt after MIC */ mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE); - if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3, + if (aes_siv_encrypt(sta->aek, sizeof(sta->aek), ampe_ie, 2 + len, 3, aad, aad_len, mic_payload)) { wpa_printf(MSG_ERROR, "protect frame: failed to encrypt"); ret = -ENOMEM; @@ -605,13 +643,13 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, size_t crypt_len; const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat }; const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, - (elems->mic - 2) - cat }; + elems->mic ? (elems->mic - 2) - cat : 0 }; size_t key_len; if (!sta->sae) { struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; - if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) { + if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL)) { wpa_printf(MSG_INFO, "Mesh RSN: SAE is not prepared yet"); return -1; @@ -619,7 +657,9 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, mesh_rsn_auth_sae_sta(wpa_s, sta); } - if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) { + if (chosen_pmk && + (!sta->sae || + os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN) != 0)) { wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)"); return -1; @@ -650,7 +690,7 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, os_memcpy(crypt, elems->mic, crypt_len); - if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3, + if (aes_siv_decrypt(sta->aek, sizeof(sta->aek), crypt, crypt_len, 3, aad, aad_len, ampe_buf)) { wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!"); ret = -2; diff --git a/contrib/wpa/wpa_supplicant/notify.c b/contrib/wpa/wpa_supplicant/notify.c index 67e36ae34cb8..bedb74b34440 100644 --- a/contrib/wpa/wpa_supplicant/notify.c +++ b/contrib/wpa/wpa_supplicant/notify.c @@ -15,7 +15,6 @@ #include "wps_supplicant.h" #include "binder/binder.h" #include "dbus/dbus_common.h" -#include "dbus/dbus_old.h" #include "dbus/dbus_new.h" #include "rsn_supp/wpa.h" #include "fst/fst.h" @@ -27,13 +26,13 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global) { -#ifdef CONFIG_DBUS +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW if (global->params.dbus_ctrl_interface) { global->dbus = wpas_dbus_init(global); if (global->dbus == NULL) return -1; } -#endif /* CONFIG_DBUS */ +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #ifdef CONFIG_BINDER global->binder = wpas_binder_init(global); @@ -47,10 +46,10 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global) void wpas_notify_supplicant_deinitialized(struct wpa_global *global) { -#ifdef CONFIG_DBUS +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW if (global->dbus) wpas_dbus_deinit(global->dbus); -#endif /* CONFIG_DBUS */ +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #ifdef CONFIG_BINDER if (global->binder) @@ -64,9 +63,6 @@ int wpas_notify_iface_added(struct wpa_supplicant *wpa_s) if (wpa_s->p2p_mgmt) return 0; - if (wpas_dbus_register_iface(wpa_s)) - return -1; - if (wpas_dbus_register_interface(wpa_s)) return -1; @@ -79,9 +75,6 @@ void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s) if (wpa_s->p2p_mgmt) return; - /* unregister interface in old DBus ctrl iface */ - wpas_dbus_unregister_iface(wpa_s); - /* unregister interface in new DBus ctrl iface */ wpas_dbus_unregister_interface(wpa_s); } @@ -94,10 +87,6 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, if (wpa_s->p2p_mgmt) return; - /* notify the old DBus API */ - wpa_supplicant_dbus_notify_state_change(wpa_s, new_state, - old_state); - /* notify the new DBus API */ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE); @@ -140,6 +129,15 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s) } +void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AUTH_STATUS_CODE); +} + + void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) @@ -149,6 +147,42 @@ void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s) } +void wpas_notify_roam_time(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_TIME); +} + + +void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_COMPLETE); +} + + +void wpas_notify_session_length(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SESSION_LENGTH); +} + + +void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSS_TM_STATUS); +} + + void wpas_notify_network_changed(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) @@ -222,9 +256,6 @@ void wpas_notify_scanning(struct wpa_supplicant *wpa_s) if (wpa_s->p2p_mgmt) return; - /* notify the old DBus API */ - wpa_supplicant_dbus_notify_scanning(wpa_s); - /* notify the new DBus API */ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING); } @@ -244,9 +275,6 @@ void wpas_notify_scan_results(struct wpa_supplicant *wpa_s) if (wpa_s->p2p_mgmt) return; - /* notify the old DBus API */ - wpa_supplicant_dbus_notify_scan_results(wpa_s); - wpas_wps_notify_scan_results(wpa_s); } @@ -258,8 +286,6 @@ void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s, return; #ifdef CONFIG_WPS - /* notify the old DBus API */ - wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred); /* notify the new DBus API */ wpas_dbus_signal_wps_cred(wpa_s, cred); #endif /* CONFIG_WPS */ @@ -669,12 +695,12 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int persistent, - int client) + int client, const u8 *ip) { /* Notify a group has been started */ wpas_dbus_register_p2p_group(wpa_s, ssid); - wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent); + wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent, ip); } @@ -720,6 +746,9 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr); #endif /* CONFIG_P2P */ + /* Register the station */ + wpas_dbus_register_sta(wpa_s, sta); + /* Notify listeners a new station has been authorized */ wpas_dbus_signal_sta_authorized(wpa_s, sta); } @@ -740,6 +769,9 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s, /* Notify listeners a station has been deauthorized */ wpas_dbus_signal_sta_deauthorized(wpa_s, sta); + + /* Unregister the station */ + wpas_dbus_unregister_sta(wpa_s, sta); } @@ -787,9 +819,6 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, "depth=%d %s", depth, altsubject[i]); } - /* notify the old DBus API */ - wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject, - cert_hash, cert); /* notify the new DBus API */ wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject, num_altsubject, cert_hash, cert); @@ -816,6 +845,12 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, } +void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code) +{ + wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_EAP_ERROR_CODE "%d", error_code); +} + + void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -850,3 +885,49 @@ void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ } + + +#ifdef CONFIG_MESH + +void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_mesh_group_started(wpa_s, ssid); +} + + +void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s, + const u8 *meshid, u8 meshid_len, + int reason_code) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_mesh_group_removed(wpa_s, meshid, meshid_len, + reason_code); +} + + +void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_mesh_peer_connected(wpa_s, peer_addr); +} + + +void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int reason_code) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_mesh_peer_disconnected(wpa_s, peer_addr, reason_code); +} + +#endif /* CONFIG_MESH */ diff --git a/contrib/wpa/wpa_supplicant/notify.h b/contrib/wpa/wpa_supplicant/notify.h index 8cce0f30c2a9..65f513ea9770 100644 --- a/contrib/wpa/wpa_supplicant/notify.h +++ b/contrib/wpa/wpa_supplicant/notify.h @@ -23,7 +23,12 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state); void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s); +void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s); void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s); +void wpas_notify_roam_time(struct wpa_supplicant *wpa_s); +void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s); +void wpas_notify_session_length(struct wpa_supplicant *wpa_s); +void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s); void wpas_notify_network_changed(struct wpa_supplicant *wpa_s); void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s); void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s); @@ -114,7 +119,7 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, unsigned int generated_pin); void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int persistent, - int client); + int client, const u8 *ip); void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s, const char *reason); void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s, @@ -134,6 +139,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *ie, size_t ie_len, u32 ssi_signal); void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); +void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code); void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, @@ -141,5 +147,14 @@ void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr, const u8 *bssid, int id, int op_freq); +void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s, + const u8 *meshid, u8 meshid_len, + int 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); #endif /* NOTIFY_H */ diff --git a/contrib/wpa/wpa_supplicant/offchannel.c b/contrib/wpa/wpa_supplicant/offchannel.c index 26d41a4ad5c6..b74be7dad4ac 100644 --- a/contrib/wpa/wpa_supplicant/offchannel.c +++ b/contrib/wpa/wpa_supplicant/offchannel.c @@ -310,6 +310,8 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, iface = wpas_get_tx_interface(wpa_s, src); wpa_s->action_tx_wait_time = wait_time; + if (wait_time) + wpa_s->action_tx_wait_time_used = 1; ret = wpa_drv_send_action( iface, wpa_s->pending_action_freq, @@ -398,13 +400,14 @@ void offchannel_send_action_done(struct wpa_supplicant *wpa_s) wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX && - wpa_s->action_tx_wait_time) + (wpa_s->action_tx_wait_time || wpa_s->action_tx_wait_time_used)) wpa_drv_send_action_cancel_wait(wpa_s); else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_drv_cancel_remain_on_channel(wpa_s); wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } + wpa_s->action_tx_wait_time_used = 0; } diff --git a/contrib/wpa/wpa_supplicant/op_classes.c b/contrib/wpa/wpa_supplicant/op_classes.c new file mode 100644 index 000000000000..947917bb05f4 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/op_classes.c @@ -0,0 +1,387 @@ +/* + * Operating classes + * Copyright(c) 2015 Intel Deutschland GmbH + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_common.h" +#include "wpa_supplicant_i.h" + + +static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan, + unsigned int *flags) +{ + int i; + + for (i = 0; i < mode->num_channels; i++) { + if (mode->channels[i].chan == chan) + break; + } + + if (i == mode->num_channels || + (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)) + return NOT_ALLOWED; + + if (flags) + *flags = mode->channels[i].flag; + + if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR) + return NO_IR; + + return ALLOWED; +} + + +static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel) +{ + u8 center_channels[] = { 42, 58, 106, 122, 138, 155 }; + size_t i; + + if (mode->mode != HOSTAPD_MODE_IEEE80211A) + return 0; + + for (i = 0; i < ARRAY_SIZE(center_channels); i++) { + /* + * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48), + * so the center channel is 6 channels away from the start/end. + */ + if (channel >= center_channels[i] - 6 && + channel <= center_channels[i] + 6) + return center_channels[i]; + } + + return 0; +} + + +static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel) +{ + u8 center_chan; + unsigned int i; + unsigned int no_ir = 0; + + center_chan = get_center_80mhz(mode, channel); + if (!center_chan) + return NOT_ALLOWED; + + /* check all the channels are available */ + for (i = 0; i < 4; i++) { + unsigned int flags; + u8 adj_chan = center_chan - 6 + i * 4; + + if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED) + return NOT_ALLOWED; + + if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) || + (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) || + (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) || + (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))) + return NOT_ALLOWED; + + if (flags & HOSTAPD_CHAN_NO_IR) + no_ir = 1; + } + + if (no_ir) + return NO_IR; + + return ALLOWED; +} + + +static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel) +{ + u8 center_channels[] = { 50, 114 }; + unsigned int i; + + if (mode->mode != HOSTAPD_MODE_IEEE80211A) + return 0; + + for (i = 0; i < ARRAY_SIZE(center_channels); i++) { + /* + * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64), + * so the center channel is 14 channels away from the start/end. + */ + if (channel >= center_channels[i] - 14 && + channel <= center_channels[i] + 14) + return center_channels[i]; + } + + return 0; +} + + +static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, + u8 channel) +{ + u8 center_chan; + unsigned int i; + unsigned int no_ir = 0; + + center_chan = get_center_160mhz(mode, channel); + if (!center_chan) + return NOT_ALLOWED; + + /* Check all the channels are available */ + for (i = 0; i < 8; i++) { + unsigned int flags; + u8 adj_chan = center_chan - 14 + i * 4; + + if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED) + return NOT_ALLOWED; + + if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) || + (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) || + (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) || + (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) || + (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) || + (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) || + (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) || + (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))) + return NOT_ALLOWED; + + if (flags & HOSTAPD_CHAN_NO_IR) + no_ir = 1; + } + + if (no_ir) + return NO_IR; + + return ALLOWED; +} + + +enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel, + u8 bw) +{ + unsigned int flag = 0; + enum chan_allowed res, res2; + + res2 = res = allow_channel(mode, channel, &flag); + if (bw == BW40MINUS) { + if (!(flag & HOSTAPD_CHAN_HT40MINUS)) + return NOT_ALLOWED; + res2 = allow_channel(mode, channel - 4, NULL); + } else if (bw == BW40PLUS) { + if (!(flag & HOSTAPD_CHAN_HT40PLUS)) + return NOT_ALLOWED; + res2 = allow_channel(mode, 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); + } 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); + } 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); + } + + if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) + return NOT_ALLOWED; + + if (res == NO_IR || res2 == NO_IR) + return NO_IR; + + return ALLOWED; +} + + +static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + const struct oper_class_map *op_class) +{ + int chan; + size_t i; + struct hostapd_hw_modes *mode; + int found; + int z; + int freq2 = 0; + int freq5 = 0; + + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode); + if (!mode) + return 0; + + /* If we are configured to disable certain things, take that into + * account here. */ + if (ssid->freq_list && ssid->freq_list[0]) { + for (z = 0; ; z++) { + int f = ssid->freq_list[z]; + + if (f == 0) + break; /* end of list */ + if (f > 4000 && f < 6000) + freq5 = 1; + else if (f > 2400 && f < 2500) + freq2 = 1; + } + } else { + /* No frequencies specified, can use anything hardware supports. + */ + freq2 = freq5 = 1; + } + + if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5) + return 0; + if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2) + return 0; + +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht) { + switch (op_class->op_class) { + case 83: + case 84: + case 104: + case 105: + case 116: + case 117: + case 119: + case 120: + case 122: + case 123: + case 126: + case 127: + case 128: + case 129: + case 130: + /* Disable >= 40 MHz channels if HT is disabled */ + return 0; + } + } +#endif /* CONFIG_HT_OVERRIDES */ + +#ifdef CONFIG_VHT_OVERRIDES + if (ssid->disable_vht) { + if (op_class->op_class >= 128 && op_class->op_class <= 130) { + /* Disable >= 80 MHz channels if VHT is disabled */ + return 0; + } + } +#endif /* CONFIG_VHT_OVERRIDES */ + + if (op_class->op_class == 128) { + u8 channels[] = { 42, 58, 106, 122, 138, 155 }; + + for (i = 0; i < ARRAY_SIZE(channels); i++) { + if (verify_channel(mode, channels[i], op_class->bw) != + NOT_ALLOWED) + return 1; + } + + return 0; + } + + 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; + } + + 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) + 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) + found++; + if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED && + verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED) + found++; + if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED) + found++; + + if (found >= 2) + return 1; + + return 0; + } + + 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) { + found = 1; + break; + } + } + + return found; +} + + +size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + int freq, u8 *pos, size_t len) +{ + struct wpabuf *buf; + u8 op, current, chan; + u8 *ie_len; + size_t res; + + /* + * Assume 20 MHz channel for now. + * TODO: Use the secondary channel and VHT channel width that will be + * used after association. + */ + if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT, + ¤t, &chan) == NUM_HOSTAPD_MODES) + return 0; + + /* + * Need 3 bytes for EID, length, and current operating class, plus + * 1 byte for every other supported operating class. + */ + buf = wpabuf_alloc(global_op_class_size + 3); + if (!buf) + return 0; + + wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES); + /* Will set the length later, putting a placeholder */ + ie_len = wpabuf_put(buf, 1); + wpabuf_put_u8(buf, current); + + for (op = 0; global_op_class[op].op_class; op++) { + if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op])) + wpabuf_put_u8(buf, global_op_class[op].op_class); + } + + *ie_len = wpabuf_len(buf) - 2; + if (*ie_len < 2 || wpabuf_len(buf) > len) { + wpa_printf(MSG_ERROR, + "Failed to add supported operating classes IE"); + res = 0; + } else { + os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf)); + res = wpabuf_len(buf); + wpa_hexdump_buf(MSG_DEBUG, + "Added supported operating classes IE", buf); + } + + wpabuf_free(buf); + return res; +} diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.c b/contrib/wpa/wpa_supplicant/p2p_supplicant.c index b1fdc2837ff0..e7c1f5d5aca4 100644 --- a/contrib/wpa/wpa_supplicant/p2p_supplicant.c +++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.c @@ -307,7 +307,14 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) return; } + if (wpa_s->clear_driver_scan_cache) { + wpa_printf(MSG_DEBUG, + "Request driver to clear scan cache due to local BSS flush"); + params->only_new_results = 1; + } ret = wpa_drv_scan(wpa_s, params); + if (ret == 0) + wpa_s->curr_scan_cookie = params->scan_cookie; wpa_scan_free_params(params); work->ctx = NULL; if (ret) { @@ -320,6 +327,7 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; wpa_s->own_scan_requested = 1; + wpa_s->clear_driver_scan_cache = 0; wpa_s->p2p_scan_work = work; } @@ -740,6 +748,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, conncap = P2PS_SETUP_GROUP_OWNER; goto grp_owner; } + /* fall through */ default: return P2PS_SETUP_NONE; @@ -807,7 +816,7 @@ grp_owner: wpa_s->own_addr); } else if (!s && !go_wpa_s) { if (wpas_p2p_add_group_interface(wpa_s, - WPA_IF_P2P_GO) < 0) { + WPA_IF_P2P_GROUP) < 0) { wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new interface for the group"); return P2PS_SETUP_NONE; @@ -971,6 +980,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, os_free(wpa_s->p2p_group_common_freqs); wpa_s->p2p_group_common_freqs = NULL; wpa_s->p2p_group_common_freqs_num = 0; + wpa_s->p2p_go_do_acs = 0; wpa_s->waiting_presence_resp = 0; @@ -1312,6 +1322,10 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, if (wpa_s->p2p_go_group_formation_completed) { wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; + } else if (wpa_s->p2p_in_provisioning && !success) { + wpa_msg(wpa_s, MSG_DEBUG, + "P2P: Stop provisioning state due to failure"); + wpa_s->p2p_in_provisioning = 0; } wpa_s->p2p_in_invitation = 0; wpa_s->group_formation_reported = 1; @@ -1383,7 +1397,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, } if (!client) { - wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0); + wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0, NULL); os_get_reltime(&wpa_s->global->p2p_go_wait_client); } } @@ -1571,20 +1585,27 @@ static int wpas_send_action_work(struct wpa_supplicant *wpa_s, static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time) + size_t len, unsigned int wait_time, int *scheduled) { struct wpa_supplicant *wpa_s = ctx; int listen_freq = -1, send_freq = -1; + if (scheduled) + *scheduled = 0; if (wpa_s->p2p_listen_work) listen_freq = wpa_s->p2p_listen_work->freq; if (wpa_s->p2p_send_action_work) send_freq = wpa_s->p2p_send_action_work->freq; if (listen_freq != (int) freq && send_freq != (int) freq) { - wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)", - listen_freq, send_freq); - return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, - len, wait_time); + int res; + + wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u)", + listen_freq, send_freq, freq); + res = wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, + len, wait_time); + if (res == 0 && scheduled) + *scheduled = 1; + return res; } wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX"); @@ -1636,7 +1657,7 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s, wpa_supplicant_ap_deinit(wpa_s); wpas_copy_go_neg_results(wpa_s, res); if (res->wps_method == WPS_PBC) { - wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1); + wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0); #ifdef CONFIG_WPS_NFC } else if (res->wps_method == WPS_NFC) { wpas_wps_start_nfc(wpa_s, res->peer_device_addr, @@ -1701,14 +1722,23 @@ static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s, static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s) { + char buf[20 + P2P_MAX_CHANNELS * 6]; + char *pos, *end; unsigned int i; + int res; - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):", - wpa_s->p2p_group_common_freqs_num); + pos = buf; + end = pos + sizeof(buf); + for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) { + res = os_snprintf(pos, end - pos, " %d", + wpa_s->p2p_group_common_freqs[i]); + if (os_snprintf_error(end - pos, res)) + break; + pos += res; + } + *pos = '\0'; - for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) - wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", - i, wpa_s->p2p_group_common_freqs[i]); + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies:%s", buf); } @@ -1801,7 +1831,8 @@ static void p2p_go_configured(void *ctx, void *data) } wpas_notify_p2p_group_started(wpa_s, ssid, - params->persistent_group, 0); + params->persistent_group, 0, + NULL); wpas_p2p_cross_connect_setup(wpa_s); wpas_p2p_set_group_idle_timeout(wpa_s); @@ -1889,6 +1920,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, ssid->vht = params->vht; ssid->max_oper_chwidth = params->max_oper_chwidth; ssid->vht_center_freq2 = params->vht_center_freq2; + ssid->he = params->he; ssid->ssid = os_zalloc(params->ssid_len + 1); if (ssid->ssid) { os_memcpy(ssid->ssid, params->ssid, params->ssid_len); @@ -1989,6 +2021,11 @@ do { \ d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey); } d->p2p_cli_probe = s->p2p_cli_probe; + d->go_interworking = s->go_interworking; + d->go_access_network_type = s->go_access_network_type; + d->go_internet = s->go_internet; + d->go_venue_group = s->go_venue_group; + d->go_venue_type = s->go_venue_type; } @@ -2047,6 +2084,13 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s, return -1; } + if (wpa_s->conf->p2p_interface_random_mac_addr) { + random_mac_addr(wpa_s->pending_interface_addr); + wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR + " for the group", + MAC2STR(wpa_s->pending_interface_addr)); + } + if (force_ifname[0]) { wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s", force_ifname); @@ -2125,6 +2169,29 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go) wpas_p2p_clone_config(group_wpa_s, wpa_s); + if (wpa_s->conf->p2p_interface_random_mac_addr) { + if (wpa_drv_set_mac_addr(group_wpa_s, + wpa_s->pending_interface_addr) < 0) { + wpa_msg(group_wpa_s, MSG_INFO, + "Failed to set random MAC address"); + wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s, + 0); + return NULL; + } + + if (wpa_supplicant_update_mac_addr(group_wpa_s) < 0) { + wpa_msg(group_wpa_s, MSG_INFO, + "Could not update MAC address information"); + wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s, + 0); + return NULL; + } + + wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR + " for the group", + MAC2STR(wpa_s->pending_interface_addr)); + } + return group_wpa_s; } @@ -3020,7 +3087,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, MAC2STR(sa), s->id); } wpas_p2p_group_add_persistent( - wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL, + wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 1); } else if (bssid) { @@ -3246,6 +3313,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, wpa_s->p2p_go_vht_center_freq2, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht, wpa_s->p2p_go_max_oper_chwidth, + wpa_s->p2p_go_he, channels, ssid->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : @@ -3331,10 +3399,6 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s, } -enum chan_allowed { - NOT_ALLOWED, NO_IR, ALLOWED -}; - static int has_channel(struct wpa_global *global, struct hostapd_hw_modes *mode, u8 chan, int *flags) { @@ -3894,6 +3958,10 @@ static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go, /* Remove stale persistent group */ if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Remove stale persistent group id=%d", + s->id); + wpas_notify_persistent_group_removed(wpa_s, s); wpa_config_remove_network(wpa_s->conf, s->id); save_config = 1; continue; @@ -4017,6 +4085,11 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, if (persistent_go && !persistent_go->num_p2p_clients) { /* remove empty persistent GO */ + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Remove empty persistent group id=%d", + persistent_go->id); + wpas_notify_persistent_group_removed(wpa_s, + persistent_go); wpa_config_remove_network(wpa_s->conf, persistent_go->id); } @@ -4057,6 +4130,10 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, /* Remove stale persistent group */ if (stale->mode != WPAS_MODE_P2P_GO || stale->num_p2p_clients <= 1) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Remove stale persistent group id=%d", + stale->id); + wpas_notify_persistent_group_removed(wpa_s, stale); wpa_config_remove_network(wpa_s->conf, stale->id); } else { size_t i; @@ -4089,6 +4166,11 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, if (persistent_go && s != persistent_go && !persistent_go->num_p2p_clients) { /* remove empty persistent GO */ + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Remove empty persistent group id=%d", + persistent_go->id); + wpas_notify_persistent_group_removed(wpa_s, + persistent_go); wpa_config_remove_network(wpa_s->conf, persistent_go->id); /* Save config */ @@ -4106,6 +4188,9 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, return; } + wpa_s->global->pending_p2ps_group = 0; + wpa_s->global->pending_p2ps_group_freq = 0; + if (conncap == P2PS_SETUP_GROUP_OWNER) { /* * We need to copy the interface name. Simply saving a @@ -4116,8 +4201,10 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, go_ifname[0] = '\0'; if (!go_wpa_s) { - wpa_s->global->pending_p2ps_group = 1; - wpa_s->global->pending_p2ps_group_freq = freq; + if (!response_done) { + wpa_s->global->pending_p2ps_group = 1; + wpa_s->global->pending_p2ps_group_freq = freq; + } if (!wpas_p2p_create_iface(wpa_s)) os_memcpy(go_ifname, wpa_s->ifname, @@ -4141,13 +4228,14 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, if (response_done && persistent_go) { wpas_p2p_group_add_persistent( wpa_s, persistent_go, - 0, 0, freq, 0, 0, 0, 0, NULL, + 0, 0, freq, 0, 0, 0, 0, 0, NULL, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0); } else if (response_done) { - wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0); + wpas_p2p_group_add(wpa_s, 1, freq, + 0, 0, 0, 0, 0); } if (passwd_id == DEV_PW_P2PS_DEFAULT) { @@ -4196,6 +4284,10 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, if (persistent_go && !persistent_go->num_p2p_clients) { /* remove empty persistent GO */ + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Remove empty persistent group id=%d", + persistent_go->id); + wpas_notify_persistent_group_removed(wpa_s, persistent_go); wpa_config_remove_network(wpa_s->conf, persistent_go->id); } @@ -4259,11 +4351,11 @@ static int wpas_prov_disc_resp_cb(void *ctx) if (persistent_go) { wpas_p2p_group_add_persistent( - wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, NULL, + wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0); } else { - wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0); + wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0); } return 1; @@ -4281,6 +4373,54 @@ static int wpas_p2p_get_pref_freq_list(void *ctx, int go, } +int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) +{ + u8 addr[ETH_ALEN] = {0}; + + if (wpa_s->conf->p2p_device_random_mac_addr == 0) + return 0; + + if (!wpa_s->conf->ssid) { + if (random_mac_addr(addr) < 0) { + wpa_msg(wpa_s, MSG_INFO, + "Failed to generate random MAC address"); + return -EINVAL; + } + + /* Store generated MAC address. */ + os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr, addr, + ETH_ALEN); + } else { + /* If there are existing saved groups, restore last MAC address. + * if there is no last used MAC address, the last one is + * factory MAC. */ + if (is_zero_ether_addr( + wpa_s->conf->p2p_device_persistent_mac_addr)) + return 0; + os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr, + ETH_ALEN); + wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address."); + } + + if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) { + wpa_msg(wpa_s, MSG_INFO, + "Failed to set random MAC address"); + return -EINVAL; + } + + if (wpa_supplicant_update_mac_addr(wpa_s) < 0) { + wpa_msg(wpa_s, MSG_INFO, + "Could not update MAC address information"); + return -EINVAL; + } + + wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR, + MAC2STR(addr)); + + return 0; +} + + /** * wpas_p2p_init - Initialize P2P module for %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() @@ -4301,6 +4441,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) if (global->p2p) return 0; + if (wpas_p2p_mac_setup(wpa_s) < 0) { + wpa_msg(wpa_s, MSG_ERROR, + "Failed to initialize P2P random MAC address."); + return -1; + } + os_memset(&p2p, 0, sizeof(p2p)); p2p.cb_ctx = wpa_s; p2p.debug_print = wpas_p2p_debug_print; @@ -4365,7 +4511,10 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) * channel. */ if (p2p_config_get_random_social(&p2p, &p2p.reg_class, - &p2p.channel) != 0) { + &p2p.channel, + &global->p2p_go_avoid_freq, + &global->p2p_disallow_freq) != + 0) { wpa_printf(MSG_INFO, "P2P: No social channels supported by the driver - do not enable P2P"); return 0; @@ -4390,10 +4539,14 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) * other preference is indicated. */ if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class, - &p2p.op_channel) != 0) { - wpa_printf(MSG_ERROR, + &p2p.op_channel, NULL, + NULL) != 0) { + wpa_printf(MSG_INFO, "P2P: Failed to select random social channel as operation channel"); - return -1; + p2p.op_reg_class = 0; + p2p.op_channel = 0; + /* This will be overridden during group setup in + * p2p_prepare_channel(), so allow setup to continue. */ } p2p.cfg_op_channel = 0; wpa_printf(MSG_DEBUG, "P2P: Random operating channel: " @@ -4786,6 +4939,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht, wpa_s->p2p_go_max_oper_chwidth, + wpa_s->p2p_go_he, NULL, 0); return; } @@ -5003,6 +5157,12 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, params.extra_ies = wpabuf_head(ies); params.extra_ies_len = wpabuf_len(ies); + if (wpa_s->clear_driver_scan_cache) { + wpa_printf(MSG_DEBUG, + "Request driver to clear scan cache due to local BSS flush"); + params.only_new_results = 1; + } + /* * Run a scan to update BSS table and start Provision Discovery once * the new scan results become available. @@ -5012,6 +5172,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_join; wpa_s->own_scan_requested = 1; + wpa_s->clear_driver_scan_cache = 0; } wpabuf_free(ies); @@ -5076,17 +5237,18 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, os_memcpy(group->p2p_pin, wpa_s->p2p_pin, sizeof(group->p2p_pin)); group->p2p_wps_method = wpa_s->p2p_wps_method; - } else { - /* - * Need to mark the current interface for p2p_group_formation - * when a separate group interface is not used. This is needed - * to allow p2p_cancel stop a pending p2p_connect-join. - * wpas_p2p_init_group_interface() addresses this for the case - * where a separate group interface is used. - */ - wpa_s->global->p2p_group_formation = wpa_s; } + /* + * Need to mark the current interface for p2p_group_formation + * when a separate group interface is not used. This is needed + * to allow p2p_cancel stop a pending p2p_connect-join. + * wpas_p2p_init_group_interface() addresses this for the case + * where a separate group interface is used. + */ + if (group == wpa_s->parent) + wpa_s->global->p2p_group_formation = group; + group->p2p_in_provisioning = 1; group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg; @@ -5183,7 +5345,8 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq); if (!ret) { if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && - ieee80211_is_dfs(freq)) { + ieee80211_is_dfs(freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) { /* * If freq is a DFS channel and DFS is offloaded * to the driver, allow P2P GO to use it. @@ -5236,9 +5399,11 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, if (!res && max_pref_freq > 0) { *num_pref_freq = max_pref_freq; i = 0; - while (wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]) && - i < *num_pref_freq) { + while (i < *num_pref_freq && + (!p2p_supported_freq(wpa_s->global->p2p, + pref_freq_list[i]) || + wpas_p2p_disallowed_freq(wpa_s->global, + pref_freq_list[i]))) { wpa_printf(MSG_DEBUG, "P2P: preferred_freq_list[%d]=%d is disallowed", i, pref_freq_list[i]); @@ -5323,7 +5488,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int persistent_group, int auto_join, int join, int auth, int go_intent, int freq, unsigned int vht_center_freq2, int persistent_id, int pd, int ht40, int vht, - unsigned int vht_chwidth, const u8 *group_ssid, + unsigned int vht_chwidth, int he, const u8 *group_ssid, size_t group_ssid_len) { int force_freq = 0, pref_freq = 0; @@ -5368,6 +5533,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_go_vht = !!vht; wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2; wpa_s->p2p_go_max_oper_chwidth = vht_chwidth; + wpa_s->p2p_go_he = !!he; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); @@ -5601,9 +5767,11 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) &size, pref_freq_list); if (!res && size > 0) { i = 0; - while (wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]) && - i < size) { + while (i < size && + (!p2p_supported_freq(wpa_s->global->p2p, + pref_freq_list[i]) || + wpas_p2p_disallowed_freq(wpa_s->global, + pref_freq_list[i]))) { wpa_printf(MSG_DEBUG, "P2P: preferred_freq_list[%d]=%d is disallowed", i, pref_freq_list[i]); @@ -5667,7 +5835,8 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) { if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && - ieee80211_is_dfs(freq)) { + ieee80211_is_dfs(freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) { /* * If freq is a DFS channel and DFS is offloaded to the * driver, allow P2P GO to use it. @@ -5705,30 +5874,6 @@ static void wpas_p2p_select_go_freq_no_pref(struct wpa_supplicant *wpa_s, { unsigned int i, r; - /* first try some random selection of the social channels */ - if (os_get_random((u8 *) &r, sizeof(r)) < 0) - return; - - for (i = 0; i < 3; i++) { - params->freq = 2412 + ((r + i) % 3) * 25; - if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq)) - goto out; - } - - /* try all other channels in operating class 81 */ - for (i = 0; i < 11; i++) { - params->freq = 2412 + i * 5; - - /* skip social channels; covered in the previous loop */ - if (params->freq == 2412 || - params->freq == 2437 || - params->freq == 2462) - continue; - - if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq)) - goto out; - } - /* try all channels in operating class 115 */ for (i = 0; i < 4; i++) { params->freq = 5180 + i * 20; @@ -5763,6 +5908,30 @@ static void wpas_p2p_select_go_freq_no_pref(struct wpa_supplicant *wpa_s, goto out; } + /* try some random selection of the social channels */ + if (os_get_random((u8 *) &r, sizeof(r)) < 0) + return; + + for (i = 0; i < 3; i++) { + params->freq = 2412 + ((r + i) % 3) * 25; + if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq)) + goto out; + } + + /* try all other channels in operating class 81 */ + for (i = 0; i < 11; i++) { + params->freq = 2412 + i * 5; + + /* skip social channels; covered in the previous loop */ + if (params->freq == 2412 || + params->freq == 2437 || + params->freq == 2462) + continue; + + if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq)) + goto out; + } + params->freq = 0; wpa_printf(MSG_DEBUG, "P2P: No 2.4, 5, or 60 GHz channel allowed"); return; @@ -5772,10 +5941,23 @@ out: } +static int wpas_same_band(int freq1, int freq2) +{ + enum hostapd_hw_mode mode1, mode2; + u8 chan1, chan2; + + mode1 = ieee80211_freq_to_chan(freq1, &chan1); + mode2 = ieee80211_freq_to_chan(freq2, &chan2); + if (mode1 == NUM_HOSTAPD_MODES) + return 0; + return mode1 == mode2; +} + + static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params, int freq, int vht_center_freq2, int ht40, - int vht, int max_oper_chwidth, + int vht, int max_oper_chwidth, int he, const struct p2p_channels *channels) { struct wpa_used_freq_data *freqs; @@ -5788,6 +5970,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, params->role_go = 1; params->ht40 = ht40; params->vht = vht; + params->he = he; params->max_oper_chwidth = max_oper_chwidth; params->vht_center_freq2 = vht_center_freq2; @@ -5822,12 +6005,31 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, /* try using the forced freq */ if (freq) { - if (!wpas_p2p_supported_freq_go(wpa_s, channels, freq)) { + if (wpas_p2p_disallowed_freq(wpa_s->global, freq) || + !freq_included(wpa_s, channels, freq)) { wpa_printf(MSG_DEBUG, - "P2P: Forced GO freq %d MHz not accepted", + "P2P: Forced GO freq %d MHz disallowed", freq); goto fail; } + if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) { + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + ieee80211_is_dfs(freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) { + /* + * If freq is a DFS channel and DFS is offloaded + * to the driver, allow P2P GO to use it. + */ + wpa_printf(MSG_DEBUG, + "P2P: %s: The forced channel for GO (%u MHz) requires DFS and DFS is offloaded", + __func__, freq); + } else { + wpa_printf(MSG_DEBUG, + "P2P: The forced channel for GO (%u MHz) is not supported for P2P uses", + freq); + goto fail; + } + } for (i = 0; i < num; i++) { if (freqs[i].freq == freq) { @@ -5953,6 +6155,80 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, goto success; } + /* Try using a channel that allows VHT to be used with 80 MHz */ + if (wpa_s->hw.modes && wpa_s->p2p_group_common_freqs) { + for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) { + enum hostapd_hw_mode mode; + struct hostapd_hw_modes *hwmode; + u8 chan; + + cand = wpa_s->p2p_group_common_freqs[i]; + mode = ieee80211_freq_to_chan(cand, &chan); + hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, + mode); + if (!hwmode || + wpas_p2p_verify_channel(wpa_s, hwmode, chan, + BW80) != ALLOWED) + continue; + if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { + params->freq = cand; + wpa_printf(MSG_DEBUG, + "P2P: Use freq %d MHz common with the peer and allowing VHT80", + params->freq); + goto success; + } + } + } + + /* Try using a channel that allows HT to be used with 40 MHz on the same + * band so that CSA can be used */ + if (wpa_s->current_ssid && wpa_s->hw.modes && + wpa_s->p2p_group_common_freqs) { + for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) { + enum hostapd_hw_mode mode; + struct hostapd_hw_modes *hwmode; + u8 chan; + + cand = wpa_s->p2p_group_common_freqs[i]; + mode = ieee80211_freq_to_chan(cand, &chan); + hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, + mode); + if (!wpas_same_band(wpa_s->current_ssid->frequency, + cand) || + !hwmode || + (wpas_p2p_verify_channel(wpa_s, hwmode, chan, + BW40MINUS) != ALLOWED && + wpas_p2p_verify_channel(wpa_s, hwmode, chan, + BW40PLUS) != ALLOWED)) + continue; + if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { + params->freq = cand; + wpa_printf(MSG_DEBUG, + "P2P: Use freq %d MHz common with the peer, allowing HT40, and maintaining same band", + params->freq); + goto success; + } + } + } + + /* Try using one of the group common freqs on the same band so that CSA + * can be used */ + if (wpa_s->current_ssid && wpa_s->p2p_group_common_freqs) { + for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) { + cand = wpa_s->p2p_group_common_freqs[i]; + if (!wpas_same_band(wpa_s->current_ssid->frequency, + cand)) + continue; + if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { + params->freq = cand; + wpa_printf(MSG_DEBUG, + "P2P: Use freq %d MHz common with the peer and maintaining same band", + params->freq); + goto success; + } + } + } + /* Try using one of the group common freqs */ if (wpa_s->p2p_group_common_freqs) { for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) { @@ -6022,6 +6298,12 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, return NULL; } + if (go && wpa_s->p2p_go_do_acs) { + group_wpa_s->p2p_go_do_acs = wpa_s->p2p_go_do_acs; + group_wpa_s->p2p_go_acs_band = wpa_s->p2p_go_acs_band; + wpa_s->p2p_go_do_acs = 0; + } + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s", group_wpa_s->ifname); group_wpa_s->p2p_first_connection_timeout = 0; @@ -6045,7 +6327,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, */ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int vht_center_freq2, int ht40, int vht, - int max_oper_chwidth) + int max_oper_chwidth, int he) { struct p2p_go_neg_results params; @@ -6059,31 +6341,16 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND"); wpas_p2p_stop_find_oper(wpa_s); - freq = wpas_p2p_select_go_freq(wpa_s, freq); - if (freq < 0) - return -1; + if (!wpa_s->p2p_go_do_acs) { + freq = wpas_p2p_select_go_freq(wpa_s, freq); + if (freq < 0) + return -1; + } if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2, - ht40, vht, max_oper_chwidth, NULL)) + ht40, vht, max_oper_chwidth, he, NULL)) return -1; - if (params.freq && - !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) { - if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && - ieee80211_is_dfs(params.freq)) { - /* - * If freq is a DFS channel and DFS is offloaded to the - * driver, allow P2P GO to use it. - */ - wpa_printf(MSG_DEBUG, - "P2P: %s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to driver", - __func__, params.freq); - } else { - wpa_printf(MSG_DEBUG, - "P2P: The selected channel for GO (%u MHz) is not supported for P2P uses", - params.freq); - return -1; - } - } + p2p_go_params(wpa_s->global->p2p, ¶ms); params.persistent_group = persistent_group; @@ -6160,7 +6427,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, int force_freq, int neg_freq, int vht_center_freq2, int ht40, - int vht, int max_oper_chwidth, + int vht, int max_oper_chwidth, int he, const struct p2p_channels *channels, int connection_timeout, int force_scan) { @@ -6236,7 +6503,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, } if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2, - ht40, vht, max_oper_chwidth, channels)) + ht40, vht, max_oper_chwidth, he, channels)) return -1; params.role_go = 1; @@ -6559,8 +6826,14 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, wpa_s->p2p_long_listen = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || - wpa_s->p2p_in_provisioning) + wpa_s->p2p_in_provisioning) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Reject p2p_find operation%s%s", + (wpa_s->global->p2p_disabled || !wpa_s->global->p2p) ? + " (P2P disabled)" : "", + wpa_s->p2p_in_provisioning ? + " (p2p_in_provisioning)" : ""); return -1; + } wpa_supplicant_cancel_sched_scan(wpa_s); @@ -6782,7 +7055,7 @@ 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_chwidth, - int pref_freq) + int pref_freq, int he) { enum p2p_invite_role role; u8 *bssid = NULL; @@ -6800,6 +7073,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_persistent_go_freq = freq; wpa_s->p2p_go_ht40 = !!ht40; wpa_s->p2p_go_vht = !!vht; + wpa_s->p2p_go_he = !!he; wpa_s->p2p_go_max_oper_chwidth = max_chwidth; wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2; if (ssid->mode == WPAS_MODE_P2P_GO) { @@ -6946,7 +7220,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) u8 go_dev_addr[ETH_ALEN]; int persistent; int freq; - u8 ip[3 * 4]; + u8 ip[3 * 4], *ip_ptr = NULL; char ip_addr[100]; if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) { @@ -6993,6 +7267,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) ip[8], ip[9], ip[10], ip[11]); if (os_snprintf_error(sizeof(ip_addr), res)) ip_addr[0] = '\0'; + ip_ptr = ip; } wpas_p2p_group_started(wpa_s, 0, ssid, freq, @@ -7005,7 +7280,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) wpas_p2p_store_persistent_group(wpa_s->p2pdev, ssid, go_dev_addr); - wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1); + wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip_ptr); } @@ -7822,7 +8097,8 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpa_s->p2p_pd_before_go_neg, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht, - wpa_s->p2p_go_max_oper_chwidth, NULL, 0); + wpa_s->p2p_go_max_oper_chwidth, + wpa_s->p2p_go_he, NULL, 0); return ret; } @@ -8358,6 +8634,7 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent, params->go_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, + wpa_s->p2p_go_he, params->go_ssid_len ? params->go_ssid : NULL, params->go_ssid_len); } @@ -8437,7 +8714,7 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s, WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, - NULL, 0); + wpa_s->p2p_go_he, NULL, 0); } @@ -8453,7 +8730,7 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s, WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, - NULL, 0); + wpa_s->p2p_go_he, NULL, 0); if (res) return res; @@ -8838,7 +9115,7 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s) * TODO: This function may not always work correctly. For example, * when we have a running GO and a BSS on a DFS channel. */ - if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) { + if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P CSA: Failed to select new frequency for GO"); return -1; @@ -8950,7 +9227,7 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s) wpa_supplicant_ap_deinit(wpa_s); /* Reselect the GO frequency */ - if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) { + if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq"); wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL); @@ -9041,16 +9318,20 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s, unsigned int i, invalid_freq = 0, policy_move = 0, flags = 0; unsigned int timeout; int freq; + int dfs_offload; wpas_p2p_go_update_common_freqs(wpa_s); freq = wpa_s->current_ssid->frequency; + dfs_offload = (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes); for (i = 0, invalid_freq = 0; i < num; i++) { if (freqs[i].freq == freq) { flags = freqs[i].flags; /* The channel is invalid, must change it */ - if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) { + if (!p2p_supported_freq_go(wpa_s->global->p2p, freq) && + !dfs_offload) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Freq=%d MHz no longer valid for GO", freq); @@ -9060,7 +9341,7 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s, /* Freq is not used by any other station interface */ continue; } else if (!p2p_supported_freq(wpa_s->global->p2p, - freqs[i].freq)) { + freqs[i].freq) && !dfs_offload) { /* Freq is not valid for P2P use cases */ continue; } else if (wpa_s->conf->p2p_go_freq_change_policy == diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.h b/contrib/wpa/wpa_supplicant/p2p_supplicant.h index 63910d1c268e..24ec2cafc249 100644 --- a/contrib/wpa/wpa_supplicant/p2p_supplicant.h +++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.h @@ -37,18 +37,18 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int persistent_group, int auto_join, int join, int auth, int go_intent, int freq, unsigned int vht_center_freq2, int persistent_id, int pd, int ht40, int vht, - unsigned int vht_chwidth, const u8 *group_ssid, + unsigned int vht_chwidth, int he, const u8 *group_ssid, size_t group_ssid_len); int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int vht_center_freq2, int ht40, int vht, - int max_oper_chwidth); + int max_oper_chwidth, int he); int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, int force_freq, int neg_freq, int vht_center_freq2, int ht40, - int vht, int max_oper_chwidth, + int vht, int max_oper_chwidth, int he, const struct p2p_channels *channels, int connection_timeout, int force_scan); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, @@ -117,7 +117,7 @@ int wpas_p2p_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 max_oper_chwidth, int pref_freq, int he); int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, const u8 *peer_addr, const u8 *go_dev_addr); int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, @@ -211,6 +211,7 @@ int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int period, unsigned int interval, unsigned int count); int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s); +int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ diff --git a/contrib/wpa/wpa_supplicant/preauth_test.c b/contrib/wpa/wpa_supplicant/preauth_test.c index f4bba98e2a82..f2fff550aa81 100644 --- a/contrib/wpa/wpa_supplicant/preauth_test.c +++ b/contrib/wpa/wpa_supplicant/preauth_test.c @@ -143,16 +143,19 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, } -static int wpa_supplicant_add_pmkid(void *wpa_s, - const u8 *bssid, const u8 *pmkid) +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) { printf("%s - not implemented\n", __func__); return -1; } -static int wpa_supplicant_remove_pmkid(void *wpa_s, - const u8 *bssid, const u8 *pmkid) +static int wpa_supplicant_remove_pmkid(void *wpa_s, void *network_ctx, + const u8 *bssid, const u8 *pmkid, + const u8 *fils_cache_id) { printf("%s - not implemented\n", __func__); return -1; @@ -344,8 +347,8 @@ int main(int argc, char *argv[]) if (preauth_test.auth_timed_out) ret = -2; else { - ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0) - ? 0 : -3; + ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0, + NULL, 0) ? 0 : -3; } test_eapol_clean(&wpa_s); diff --git a/contrib/wpa/wpa_supplicant/rrm.c b/contrib/wpa/wpa_supplicant/rrm.c new file mode 100644 index 000000000000..cb3c6c995dd9 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/rrm.c @@ -0,0 +1,1575 @@ +/* + * wpa_supplicant - Radio Measurements + * Copyright (c) 2003-2016, 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 "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_common.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" +#include "bss.h" +#include "scan.h" +#include "p2p_supplicant.h" + + +static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx) +{ + struct rrm_data *rrm = data; + + if (!rrm->notify_neighbor_rep) { + wpa_printf(MSG_ERROR, + "RRM: Unexpected neighbor report timeout"); + return; + } + + wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE"); + rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL); + + rrm->notify_neighbor_rep = NULL; + rrm->neighbor_rep_cb_ctx = NULL; +} + + +/* + * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant + * @wpa_s: Pointer to wpa_supplicant + */ +void wpas_rrm_reset(struct wpa_supplicant *wpa_s) +{ + wpa_s->rrm.rrm_used = 0; + + eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, + NULL); + if (wpa_s->rrm.notify_neighbor_rep) + wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); + wpa_s->rrm.next_neighbor_rep_token = 1; + wpas_clear_beacon_rep_data(wpa_s); +} + + +/* + * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report + * @wpa_s: Pointer to wpa_supplicant + * @report: Neighbor report buffer, prefixed by a 1-byte dialog token + * @report_len: Length of neighbor report buffer + */ +void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, + const u8 *report, size_t report_len) +{ + struct wpabuf *neighbor_rep; + + wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len); + if (report_len < 1) + return; + + if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) { + wpa_printf(MSG_DEBUG, + "RRM: Discarding neighbor report with token %d (expected %d)", + report[0], wpa_s->rrm.next_neighbor_rep_token - 1); + return; + } + + eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, + NULL); + + if (!wpa_s->rrm.notify_neighbor_rep) { + wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report"); + return; + } + + /* skipping the first byte, which is only an id (dialog token) */ + neighbor_rep = wpabuf_alloc(report_len - 1); + if (!neighbor_rep) { + wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); + return; + } + wpabuf_put_data(neighbor_rep, report + 1, report_len - 1); + wpa_printf(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; + wpa_s->rrm.neighbor_rep_cb_ctx = NULL; +} + + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) +/* Workaround different, undefined for Windows, error codes used here */ +#define ENOTCONN -1 +#define EOPNOTSUPP -1 +#define ECANCELED -1 +#endif + +/* Measurement Request element + Location Subject + Maximum Age subelement */ +#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4) +/* Measurement Request element + Location Civic Request */ +#define MEASURE_REQUEST_CIVIC_LEN (3 + 5) + + +/** + * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP + * @wpa_s: Pointer to wpa_supplicant + * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE + * is sent in the request. + * @lci: if set, neighbor request will include LCI request + * @civic: if set, neighbor request will include civic location request + * @cb: Callback function to be called once the requested report arrives, or + * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds. + * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's + * the requester's responsibility to free it. + * In the latter case NULL will be sent in 'neighbor_rep'. + * @cb_ctx: Context value to send the callback function + * Returns: 0 in case of success, negative error code otherwise + * + * In case there is a previous request which has not been answered yet, the + * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT. + * Request must contain a callback function. + */ +int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, + const struct wpa_ssid_value *ssid, + int lci, int civic, + void (*cb)(void *ctx, + struct wpabuf *neighbor_rep), + void *cb_ctx) +{ + struct wpabuf *buf; + 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."); + return -ENOTCONN; + } + + if (!wpa_s->rrm.rrm_used) { + wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection."); + return -EOPNOTSUPP; + } + + rrm_ie = wpa_bss_get_ie(wpa_s->current_bss, + 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."); + 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."); + return -EBUSY; + } + + /* 3 = action category + action code + dialog token */ + buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) + + (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"); + 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); + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST); + wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token); + if (ssid) { + wpabuf_put_u8(buf, WLAN_EID_SSID); + wpabuf_put_u8(buf, ssid->ssid_len); + wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len); + } + + if (lci) { + /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN); + + /* + * Measurement token; nonzero number that is unique among the + * Measurement Request elements in a particular frame. + */ + wpabuf_put_u8(buf, 1); /* Measurement Token */ + + /* + * Parallel, Enable, Request, and Report bits are 0, Duration is + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */ + + /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */ + /* Location Subject */ + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + + /* Optional Subelements */ + /* + * IEEE P802.11-REVmc/D5.0 Figure 9-170 + * The Maximum Age subelement is required, otherwise the AP can + * send only data that was determined after receiving the + * request. Setting it here to unlimited age. + */ + wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); + wpabuf_put_u8(buf, 2); + wpabuf_put_le16(buf, 0xffff); + } + + if (civic) { + /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN); + + /* + * Measurement token; nonzero number that is unique among the + * Measurement Request elements in a particular frame. + */ + wpabuf_put_u8(buf, 2); /* Measurement Token */ + + /* + * Parallel, Enable, Request, and Report bits are 0, Duration is + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + /* Measurement Type */ + wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC); + + /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14: + * Location Civic request */ + /* Location Subject */ + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */ + /* Location Service Interval Units: Seconds */ + wpabuf_put_u8(buf, 0); + /* Location Service Interval: 0 - Only one report is requested + */ + wpabuf_put_le16(buf, 0); + /* No optional subelements */ + } + + wpa_s->rrm.next_neighbor_rep_token++; + + 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"); + wpabuf_free(buf); + return -ECANCELED; + } + + wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx; + wpa_s->rrm.notify_neighbor_rep = cb; + eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0, + wpas_rrm_neighbor_rep_timeout_handler, + &wpa_s->rrm, NULL); + + wpabuf_free(buf); + return 0; +} + + +static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type, + const u8 *data, size_t data_len) +{ + if (wpabuf_resize(buf, 5 + data_len)) + return -1; + + wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT); + wpabuf_put_u8(*buf, 3 + data_len); + wpabuf_put_u8(*buf, token); + wpabuf_put_u8(*buf, mode); + wpabuf_put_u8(*buf, type); + + if (data_len) + wpabuf_put_data(*buf, data, data_len); + + return 0; +} + + +static int +wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s, + const struct rrm_measurement_request_element *req, + struct wpabuf **buf) +{ + u8 subject; + u16 max_age = 0; + struct os_reltime t, diff; + unsigned long diff_l; + const u8 *subelem; + const u8 *request = req->variable; + size_t len = req->len - 3; + + if (len < 1) + return -1; + + if (!wpa_s->lci) + goto reject; + + subject = *request++; + len--; + + wpa_printf(MSG_DEBUG, "Measurement request location subject=%u", + subject); + + if (subject != LOCATION_SUBJECT_REMOTE) { + wpa_printf(MSG_INFO, + "Not building LCI report - bad location subject"); + return 0; + } + + /* Subelements are formatted exactly like elements */ + wpa_hexdump(MSG_DEBUG, "LCI request subelements", request, len); + subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE); + if (subelem && subelem[1] == 2) + max_age = WPA_GET_LE16(subelem + 2); + + if (os_get_reltime(&t)) + goto reject; + + os_reltime_sub(&t, &wpa_s->lci_time, &diff); + /* LCI age is calculated in 10th of a second units. */ + diff_l = diff.sec * 10 + diff.usec / 100000; + + if (max_age != 0xffff && max_age < diff_l) + goto reject; + + if (wpas_rrm_report_elem(buf, req->token, + MEASUREMENT_REPORT_MODE_ACCEPT, req->type, + wpabuf_head_u8(wpa_s->lci), + wpabuf_len(wpa_s->lci)) < 0) { + wpa_printf(MSG_DEBUG, "Failed to add LCI report element"); + return -1; + } + + return 0; + +reject: + if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && + wpas_rrm_report_elem(buf, req->token, + MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE, + req->type, NULL, 0) < 0) { + wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); + return -1; + } + + return 0; +} + + +static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s, + const u8 *data, size_t len) +{ + struct wpabuf *report = wpabuf_alloc(len + 3); + + if (!report) + return; + + wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT); + wpabuf_put_u8(report, wpa_s->rrm.token); + + wpabuf_put_data(report, data, len); + + if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(report), wpabuf_len(report), 0)) { + wpa_printf(MSG_ERROR, + "RRM: Radio measurement report failed: Sending Action frame failed"); + } + + wpabuf_free(report); +} + + +static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len) +{ + struct rrm_measurement_report_element *msr_rep; + u8 *end = pos + len; + u8 *msr_rep_end; + struct rrm_measurement_beacon_report *rep = NULL; + u8 *subelem; + + /* Find the last beacon report element */ + while (end - pos >= (int) sizeof(*msr_rep)) { + msr_rep = (struct rrm_measurement_report_element *) pos; + msr_rep_end = pos + msr_rep->len + 2; + + if (msr_rep->eid != WLAN_EID_MEASURE_REPORT || + msr_rep_end > end) { + /* Should not happen. This indicates a bug. */ + wpa_printf(MSG_ERROR, + "RRM: non-measurement report element in measurement report frame"); + return -1; + } + + if (msr_rep->type == MEASURE_TYPE_BEACON) + rep = (struct rrm_measurement_beacon_report *) + msr_rep->variable; + + pos += pos[1] + 2; + } + + if (!rep) + return 0; + + subelem = rep->variable; + while (subelem + 2 < msr_rep_end && + subelem[0] != WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION) + subelem += 2 + subelem[1]; + + if (subelem + 2 < msr_rep_end && + subelem[0] == WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION && + subelem[1] == 1 && + subelem + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end) + subelem[2] = 1; + + return 0; +} + + +static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s, + struct wpabuf *buf) +{ + int len = wpabuf_len(buf); + u8 *pos = wpabuf_mhead_u8(buf), *next = pos; + +#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3) + + while (len) { + int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len; + + if (send_len == len) + wpas_rrm_beacon_rep_update_last_frame(pos, len); + + if (send_len == len || + (send_len + next[1] + 2) > MPDU_REPORT_LEN) { + wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len); + len -= send_len; + pos = next; + } + + if (len) + next += next[1] + 2; + } +#undef MPDU_REPORT_LEN +} + + +static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels, + int *freqs) +{ + size_t i; + + for (i = 0; i < num_primary_channels; i++) { + u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4; + + freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan); + /* ieee80211_chan_to_freq() is not really meant for this + * conversion of 20 MHz primary channel numbers for wider VHT + * channels, so handle those as special cases here for now. */ + if (freqs[i] < 0 && + (op_class == 128 || op_class == 129 || op_class == 130)) + freqs[i] = 5000 + 5 * primary_chan; + if (freqs[i] < 0) { + wpa_printf(MSG_DEBUG, + "Beacon Report: Invalid channel %u", + chan); + return -1; + } + } + + return 0; +} + + +static int * wpas_add_channels(const struct oper_class_map *op, + struct hostapd_hw_modes *mode, int active, + const u8 *channels, const u8 size) +{ + int *freqs, *next_freq; + u8 num_primary_channels, i; + u8 num_chans; + + num_chans = channels ? size : + (op->max_chan - op->min_chan) / op->inc + 1; + + if (op->bw == BW80 || op->bw == BW80P80) + num_primary_channels = 4; + else if (op->bw == BW160) + num_primary_channels = 8; + else + num_primary_channels = 1; + + /* one extra place for the zero-terminator */ + freqs = os_calloc(num_chans * num_primary_channels + 1, sizeof(*freqs)); + if (!freqs) { + wpa_printf(MSG_ERROR, + "Beacon Report: Failed to allocate freqs array"); + return NULL; + } + + 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); + + if (res == NOT_ALLOWED || (res == NO_IR && active)) + continue; + + if (wpas_add_channel(op->op_class, chan, num_primary_channels, + next_freq) < 0) { + os_free(freqs); + return NULL; + } + + next_freq += num_primary_channels; + } + + if (!freqs[0]) { + os_free(freqs); + return NULL; + } + + return freqs; +} + + +static int * wpas_op_class_freqs(const struct oper_class_map *op, + struct hostapd_hw_modes *mode, int active) +{ + u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 }; + u8 channels_160mhz[] = { 50, 114 }; + + /* + * When adding all channels in the operating class, 80 + 80 MHz + * operating classes are like 80 MHz channels because we add all valid + * channels anyway. + */ + if (op->bw == BW80 || op->bw == BW80P80) + return wpas_add_channels(op, mode, active, channels_80mhz, + ARRAY_SIZE(channels_80mhz)); + + if (op->bw == BW160) + return wpas_add_channels(op, mode, active, channels_160mhz, + ARRAY_SIZE(channels_160mhz)); + + return wpas_add_channels(op, mode, active, NULL, 0); +} + + +static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, + const char *country, const u8 *subelems, + size_t len) +{ + int *freqs = NULL, *new_freqs; + const u8 *end = subelems + len; + + while (end - subelems > 2) { + const struct oper_class_map *op; + const u8 *ap_chan_elem, *pos; + u8 left; + struct hostapd_hw_modes *mode; + + ap_chan_elem = get_ie(subelems, end - subelems, + WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL); + if (!ap_chan_elem) + break; + pos = ap_chan_elem + 2; + left = ap_chan_elem[1]; + if (left < 1) + break; + subelems = ap_chan_elem + 2 + left; + + op = get_oper_class(country, *pos); + if (!op) { + wpa_printf(MSG_DEBUG, + "Beacon request: unknown operating class in AP Channel Report subelement %u", + *pos); + goto out; + } + pos++; + left--; + + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode); + if (!mode) + continue; + + /* + * For 80 + 80 MHz operating classes, this AP Channel Report + * element should be followed by another element specifying + * the second 80 MHz channel. For now just add this 80 MHz + * channel, the second 80 MHz channel will be added when the + * next element is parsed. + * TODO: Verify that this AP Channel Report element is followed + * by a corresponding AP Channel Report element as specified in + * IEEE Std 802.11-2016, 11.11.9.1. + */ + new_freqs = wpas_add_channels(op, mode, active, pos, left); + if (new_freqs) + int_array_concat(&freqs, new_freqs); + + os_free(new_freqs); + } + + return freqs; +out: + os_free(freqs); + return NULL; +} + + +static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, + u8 op_class, u8 chan, int active, + const u8 *subelems, size_t len) +{ + int *freqs = NULL, *ext_freqs = NULL; + struct hostapd_hw_modes *mode; + const char *country = NULL; + const struct oper_class_map *op; + const u8 *elem; + + if (!wpa_s->current_bss) + return NULL; + elem = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY); + if (elem && elem[1] >= 2) + country = (const char *) (elem + 2); + + op = get_oper_class(country, op_class); + if (!op) { + wpa_printf(MSG_DEBUG, + "Beacon request: invalid operating class %d", + op_class); + return NULL; + } + + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode); + if (!mode) + return NULL; + + switch (chan) { + case 0: + freqs = wpas_op_class_freqs(op, mode, active); + if (!freqs) + return NULL; + break; + case 255: + /* freqs will be added from AP channel subelements */ + break; + default: + freqs = wpas_add_channels(op, mode, active, &chan, 1); + if (!freqs) + return NULL; + break; + } + + ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems, + len); + if (ext_freqs) { + int_array_concat(&freqs, ext_freqs); + os_free(ext_freqs); + int_array_sort_unique(freqs); + } + + return freqs; +} + + +static 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; + struct ieee80211_ht_operation *ht_oper = NULL; + struct ieee80211_vht_operation *vht_oper = NULL; + u8 seg0, seg1; + + ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); + if (ie && ie[1] >= sizeof(struct ieee80211_ht_operation)) { + u8 sec_chan_offset; + + ht_oper = (struct ieee80211_ht_operation *) (ie + 2); + sec_chan_offset = ht_oper->ht_param & + HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; + if (sec_chan_offset == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) + sec_chan = 1; + else if (sec_chan_offset == + HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) + sec_chan = -1; + } + + ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); + if (ie && ie[1] >= sizeof(struct ieee80211_vht_operation)) { + vht_oper = (struct ieee80211_vht_operation *) (ie + 2); + + switch (vht_oper->vht_op_info_chwidth) { + case 1: + 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; + else if (seg1) + vht = VHT_CHANWIDTH_80P80MHZ; + else + vht = VHT_CHANWIDTH_80MHZ; + break; + case 2: + vht = VHT_CHANWIDTH_160MHZ; + break; + case 3: + vht = VHT_CHANWIDTH_80P80MHZ; + break; + default: + vht = VHT_CHANWIDTH_USE_HT; + break; + } + } + + if (ieee80211_freq_to_channel_ext(freq, sec_chan, vht, op_class, + chan) == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_DEBUG, + "Cannot determine operating class and channel"); + return -1; + } + + *phy_type = ieee80211_get_phy_type(freq, ht_oper != NULL, + vht_oper != NULL); + if (*phy_type == PHY_TYPE_UNSPECIFIED) { + wpa_printf(MSG_DEBUG, "Cannot determine phy type"); + return -1; + } + + return 0; +} + + +static int wpas_beacon_rep_add_frame_body(struct bitfield *eids, + enum beacon_report_detail detail, + struct wpa_bss *bss, u8 *buf, + size_t buf_len, u8 **ies_buf, + size_t *ie_len, int add_fixed) +{ + u8 *ies = *ies_buf; + size_t ies_len = *ie_len; + u8 *pos = buf; + int rem_len; + + rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) - + sizeof(struct rrm_measurement_report_element) - 2 - + REPORTED_FRAME_BODY_SUBELEM_LEN; + + if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) { + wpa_printf(MSG_DEBUG, + "Beacon Request: Invalid reporting detail: %d", + detail); + return -1; + } + + if (detail == BEACON_REPORT_DETAIL_NONE) + return 0; + + /* + * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) + + * beacon interval(2) + capabilities(2) = 14 bytes + */ + if (add_fixed && buf_len < 14) + return -1; + + *pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY; + /* The length will be filled later */ + pos++; + + if (add_fixed) { + WPA_PUT_LE64(pos, bss->tsf); + pos += sizeof(bss->tsf); + WPA_PUT_LE16(pos, bss->beacon_int); + pos += 2; + WPA_PUT_LE16(pos, bss->caps); + pos += 2; + } + + rem_len -= pos - buf; + + /* + * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame + * body subelement causes the element to exceed the maximum element + * size, the subelement is truncated so that the last IE is a complete + * IE. So even when required to report all IEs, add elements one after + * the other and stop once there is no more room in the measurement + * element. + */ + while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) { + if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS || + (eids && bitfield_is_set(eids, ies[0]))) { + u8 elen = ies[1]; + + if (2 + elen > buf + buf_len - pos || + 2 + elen > rem_len) + break; + + *pos++ = ies[0]; + *pos++ = elen; + os_memcpy(pos, ies + 2, elen); + pos += elen; + rem_len -= 2 + elen; + } + + ies_len -= 2 + ies[1]; + ies += 2 + ies[1]; + } + + *ie_len = ies_len; + *ies_buf = ies; + + /* Now the length is known */ + buf[1] = pos - buf - 2; + return pos - buf; +} + + +static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data, + struct wpa_bss *bss, + struct wpabuf **wpa_buf, + struct rrm_measurement_beacon_report *rep, + u8 **ie, size_t *ie_len, u8 idx) +{ + int ret; + u8 *buf, *pos; + u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN + + (data->last_indication ? + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0); + + /* Maximum element length: Beacon Report element + Reported Frame Body + * subelement + all IEs of the reported Beacon frame + Reported Frame + * Body Fragment ID subelement */ + buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len); + if (!buf) + return -1; + + os_memcpy(buf, rep, sizeof(*rep)); + + ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail, + bss, buf + sizeof(*rep), + 14 + *ie_len, ie, ie_len, + idx == 0); + if (ret < 0) + goto out; + + pos = buf + ret + sizeof(*rep); + pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID; + pos[1] = 2; + + /* + * Only one Beacon Report Measurement is supported at a time, so + * the Beacon Report ID can always be set to 1. + */ + pos[2] = 1; + + /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7) + */ + pos[3] = idx; + if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len) + pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS; + else + pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS; + + pos += REPORTED_FRAME_BODY_SUBELEM_LEN; + + if (data->last_indication) { + pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION; + pos[1] = 1; + + /* This field will be updated later if this is the last frame */ + pos[2] = 0; + } + + ret = wpas_rrm_report_elem(wpa_buf, data->token, + MEASUREMENT_REPORT_MODE_ACCEPT, + MEASURE_TYPE_BEACON, buf, + ret + sizeof(*rep) + subelems_len); +out: + os_free(buf); + return ret; +} + + +static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s, + struct wpabuf **wpa_buf, struct wpa_bss *bss, + u64 start, u64 parent_tsf) +{ + struct beacon_rep_data *data = &wpa_s->beacon_rep_data; + u8 *ies = (u8 *) (bss + 1); + u8 *pos = ies; + size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + struct rrm_measurement_beacon_report rep; + u8 idx = 0; + + if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 && + os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0) + return 0; + + if (data->ssid_len && + (data->ssid_len != bss->ssid_len || + os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0)) + return 0; + + if (wpas_get_op_chan_phy(bss->freq, ies, ies_len, &rep.op_class, + &rep.channel, &rep.report_info) < 0) + return 0; + + rep.start_time = host_to_le64(start); + rep.duration = host_to_le16(data->scan_params.duration); + rep.rcpi = rssi_to_rcpi(bss->level); + rep.rsni = 255; /* 255 indicates that RSNI is not available */ + os_memcpy(rep.bssid, bss->bssid, ETH_ALEN); + rep.antenna_id = 0; /* unknown */ + rep.parent_tsf = host_to_le32(parent_tsf); + + do { + int ret; + + ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep, + &pos, &ies_len, idx++); + if (ret) + return ret; + } while (data->report_detail != BEACON_REPORT_DETAIL_NONE && + ies_len >= 2); + + return 0; +} + + +static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s, + struct wpabuf **buf) +{ + return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token, + MEASUREMENT_REPORT_MODE_ACCEPT, + MEASURE_TYPE_BEACON, NULL, 0); +} + + +static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s, + struct wpabuf **buf) +{ + size_t i; + + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i], + 0, 0) < 0) + break; + } + + if (!(*buf)) + wpas_beacon_rep_no_results(wpa_s, buf); + + wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf); +} + + +void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s) +{ + if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) { + struct wpabuf *buf = NULL; + + if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token, + MEASUREMENT_REPORT_MODE_REJECT_REFUSED, + MEASURE_TYPE_BEACON, NULL, 0)) { + wpa_printf(MSG_ERROR, "RRM: Memory allocation failed"); + wpabuf_free(buf); + return; + } + + wpas_rrm_send_msr_report(wpa_s, buf); + wpabuf_free(buf); + } + + wpas_clear_beacon_rep_data(wpa_s); +} + + +static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct wpa_driver_scan_params *params = + &wpa_s->beacon_rep_data.scan_params; + u16 prev_duration = params->duration; + + if (!wpa_s->current_bss) + return; + + if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) && + params->duration) { + wpa_printf(MSG_DEBUG, + "RRM: Cannot set scan duration due to missing driver support"); + params->duration = 0; + } + os_get_reltime(&wpa_s->beacon_rep_scan); + if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) || + wpa_supplicant_trigger_scan(wpa_s, params)) + wpas_rrm_refuse_request(wpa_s); + params->duration = prev_duration; +} + + +static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s, + struct beacon_rep_data *data, + u8 sid, u8 slen, const u8 *subelem) +{ + u8 report_info, i; + + switch (sid) { + case WLAN_BEACON_REQUEST_SUBELEM_SSID: + if (!slen) { + wpa_printf(MSG_DEBUG, + "SSID subelement with zero length - wildcard SSID"); + break; + } + + if (slen > SSID_MAX_LEN) { + wpa_printf(MSG_DEBUG, + "Invalid SSID subelement length: %u", slen); + return -1; + } + + data->ssid_len = slen; + os_memcpy(data->ssid, subelem, data->ssid_len); + break; + case WLAN_BEACON_REQUEST_SUBELEM_INFO: + if (slen != 2) { + wpa_printf(MSG_DEBUG, + "Invalid reporting information subelement length: %u", + slen); + return -1; + } + + report_info = subelem[0]; + if (report_info != 0) { + wpa_printf(MSG_DEBUG, + "reporting information=%u is not supported", + report_info); + return 0; + } + break; + case WLAN_BEACON_REQUEST_SUBELEM_DETAIL: + if (slen != 1) { + wpa_printf(MSG_DEBUG, + "Invalid reporting detail subelement length: %u", + slen); + return -1; + } + + data->report_detail = subelem[0]; + if (data->report_detail > + BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) { + wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u", + subelem[0]); + return -1; + } + + break; + case WLAN_BEACON_REQUEST_SUBELEM_REQUEST: + if (data->report_detail != + BEACON_REPORT_DETAIL_REQUESTED_ONLY) { + wpa_printf(MSG_DEBUG, + "Beacon request: request subelement is present but report detail is %u", + data->report_detail); + return -1; + } + + if (!slen) { + wpa_printf(MSG_DEBUG, + "Invalid request subelement length: %u", + slen); + return -1; + } + + if (data->eids) { + wpa_printf(MSG_DEBUG, + "Beacon Request: Request subelement appears more than once"); + return -1; + } + + data->eids = bitfield_alloc(255); + if (!data->eids) { + wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap"); + return -1; + } + + for (i = 0; i < slen; i++) + bitfield_set(data->eids, subelem[i]); + break; + case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL: + /* Skip - it will be processed when freqs are added */ + break; + case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION: + if (slen != 1) { + wpa_printf(MSG_DEBUG, + "Beacon request: Invalid last indication request subelement length: %u", + slen); + return -1; + } + + data->last_indication = subelem[0]; + break; + default: + wpa_printf(MSG_DEBUG, + "Beacon request: Unknown subelement id %u", sid); + break; + } + + return 1; +} + + +/** + * Returns 0 if the next element can be processed, 1 if some operation was + * triggered, and -1 if processing failed (i.e., the element is in invalid + * format or an internal error occurred). + */ +static int +wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s, + u8 elem_token, int duration_mandatory, + const struct rrm_measurement_beacon_request *req, + size_t len, struct wpabuf **buf) +{ + struct beacon_rep_data *data = &wpa_s->beacon_rep_data; + struct wpa_driver_scan_params *params = &data->scan_params; + const u8 *subelems; + size_t elems_len; + u16 rand_interval; + u32 interval_usec; + u32 _rand; + int ret = 0, res; + u8 reject_mode; + + if (len < sizeof(*req)) + return -1; + + if (req->mode != BEACON_REPORT_MODE_PASSIVE && + req->mode != BEACON_REPORT_MODE_ACTIVE && + req->mode != BEACON_REPORT_MODE_TABLE) + return 0; + + subelems = req->variable; + elems_len = len - sizeof(*req); + rand_interval = le_to_host16(req->rand_interval); + + os_free(params->freqs); + os_memset(params, 0, sizeof(*params)); + + data->token = elem_token; + + /* default reporting detail is all fixed length fields and all + * elements */ + data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS; + os_memcpy(data->bssid, req->bssid, ETH_ALEN); + + while (elems_len >= 2) { + if (subelems[1] > elems_len - 2) { + wpa_printf(MSG_DEBUG, + "Beacon Request: Truncated subelement"); + ret = -1; + goto out; + } + + res = wpas_rm_handle_beacon_req_subelem( + wpa_s, data, subelems[0], subelems[1], &subelems[2]); + if (res < 0) { + ret = res; + goto out; + } else if (!res) { + reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE; + goto out_reject; + } + + elems_len -= 2 + subelems[1]; + subelems += 2 + subelems[1]; + } + + if (req->mode == BEACON_REPORT_MODE_TABLE) { + wpas_beacon_rep_table(wpa_s, buf); + goto out; + } + + params->freqs = wpas_beacon_request_freqs( + wpa_s, req->oper_class, req->channel, + req->mode == BEACON_REPORT_MODE_ACTIVE, + req->variable, len - sizeof(*req)); + if (!params->freqs) { + wpa_printf(MSG_DEBUG, "Beacon request: No valid channels"); + reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED; + goto out_reject; + } + + params->duration = le_to_host16(req->duration); + params->duration_mandatory = duration_mandatory; + if (!params->duration) { + wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0"); + ret = -1; + goto out; + } + + params->only_new_results = 1; + + if (req->mode == BEACON_REPORT_MODE_ACTIVE) { + params->ssids[params->num_ssids].ssid = data->ssid; + params->ssids[params->num_ssids++].ssid_len = data->ssid_len; + } + + if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) + _rand = os_random(); + interval_usec = (_rand % (rand_interval + 1)) * 1024; + eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s, + NULL); + return 1; +out_reject: + if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && + wpas_rrm_report_elem(buf, elem_token, reject_mode, + MEASURE_TYPE_BEACON, NULL, 0) < 0) { + wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); + ret = -1; + } +out: + wpas_clear_beacon_rep_data(wpa_s); + return ret; +} + + +static int +wpas_rrm_handle_msr_req_element( + struct wpa_supplicant *wpa_s, + const struct rrm_measurement_request_element *req, + struct wpabuf **buf) +{ + int duration_mandatory; + + wpa_printf(MSG_DEBUG, "Measurement request type %d token %d", + req->type, req->token); + + if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) { + /* Enable bit is not supported for now */ + wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore"); + return 0; + } + + if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) && + req->type > MEASURE_TYPE_RPI_HIST) { + /* Parallel measurements are not supported for now */ + wpa_printf(MSG_DEBUG, + "RRM: Parallel measurements are not supported, reject"); + goto reject; + } + + duration_mandatory = + !!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY); + + switch (req->type) { + case MEASURE_TYPE_LCI: + return wpas_rrm_build_lci_report(wpa_s, req, buf); + case MEASURE_TYPE_BEACON: + if (duration_mandatory && + !(wpa_s->drv_rrm_flags & + WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL)) { + wpa_printf(MSG_DEBUG, + "RRM: Driver does not support dwell time configuration - reject beacon report with mandatory duration"); + goto reject; + } + return wpas_rm_handle_beacon_req(wpa_s, req->token, + duration_mandatory, + (const void *) req->variable, + req->len - 3, buf); + default: + wpa_printf(MSG_INFO, + "RRM: Unsupported radio measurement type %u", + req->type); + break; + } + +reject: + if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && + wpas_rrm_report_elem(buf, req->token, + MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE, + req->type, NULL, 0) < 0) { + wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); + return -1; + } + + return 0; +} + + +static struct wpabuf * +wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos, + size_t len) +{ + struct wpabuf *buf = NULL; + + while (len) { + const struct rrm_measurement_request_element *req; + int res; + + if (len < 2) { + wpa_printf(MSG_DEBUG, "RRM: Truncated element"); + goto out; + } + + req = (const struct rrm_measurement_request_element *) pos; + if (req->eid != WLAN_EID_MEASURE_REQUEST) { + wpa_printf(MSG_DEBUG, + "RRM: Expected Measurement Request element, but EID is %u", + req->eid); + goto out; + } + + if (req->len < 3) { + wpa_printf(MSG_DEBUG, "RRM: Element length too short"); + goto out; + } + + if (req->len > len - 2) { + wpa_printf(MSG_DEBUG, "RRM: Element length too long"); + goto out; + } + + res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf); + if (res < 0) + goto out; + + pos += req->len + 2; + len -= req->len + 2; + } + + return buf; + +out: + wpabuf_free(buf); + return NULL; +} + + +void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, + const u8 *src, const u8 *dst, + const u8 *frame, size_t len) +{ + struct wpabuf *report; + + if (wpa_s->wpa_state != WPA_COMPLETED) { + wpa_printf(MSG_INFO, + "RRM: Ignoring radio measurement request: Not associated"); + return; + } + + if (!wpa_s->rrm.rrm_used) { + wpa_printf(MSG_INFO, + "RRM: Ignoring radio measurement request: Not RRM network"); + return; + } + + if (len < 3) { + wpa_printf(MSG_INFO, + "RRM: Ignoring too short radio measurement request"); + return; + } + + wpa_s->rrm.token = *frame; + os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN); + + /* Number of repetitions is not supported */ + + report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3); + if (!report) + return; + + wpas_rrm_send_msr_report(wpa_s, report); + wpabuf_free(report); +} + + +void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, + const u8 *src, + const u8 *frame, size_t len, + int rssi) +{ + struct wpabuf *buf; + const struct rrm_link_measurement_request *req; + struct rrm_link_measurement_report report; + + if (wpa_s->wpa_state != WPA_COMPLETED) { + wpa_printf(MSG_INFO, + "RRM: Ignoring link measurement request. Not associated"); + return; + } + + if (!wpa_s->rrm.rrm_used) { + wpa_printf(MSG_INFO, + "RRM: Ignoring link measurement request. Not RRM network"); + return; + } + + if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { + wpa_printf(MSG_INFO, + "RRM: Measurement report failed. TX power insertion not supported"); + return; + } + + req = (const struct rrm_link_measurement_request *) frame; + if (len < sizeof(*req)) { + wpa_printf(MSG_INFO, + "RRM: Link measurement report failed. Request too short"); + return; + } + + os_memset(&report, 0, sizeof(report)); + report.dialog_token = req->dialog_token; + report.tpc.eid = WLAN_EID_TPC_REPORT; + report.tpc.len = 2; + /* Note: The driver is expected to update report.tpc.tx_power and + * report.tpc.link_margin subfields when sending out this frame. + * Similarly, the driver would need to update report.rx_ant_id and + * report.tx_ant_id subfields. */ + report.rsni = 255; /* 255 indicates that RSNI is not available */ + report.rcpi = rssi_to_rcpi(rssi); + + /* action_category + action_code */ + buf = wpabuf_alloc(2 + sizeof(report)); + if (buf == NULL) { + wpa_printf(MSG_ERROR, + "RRM: Link measurement report failed. Buffer allocation failed"); + return; + } + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT); + wpabuf_put_data(buf, &report, sizeof(report)); + wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf); + + if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(buf), wpabuf_len(buf), 0)) { + wpa_printf(MSG_ERROR, + "RRM: Link measurement report failed. Send action failed"); + } + wpabuf_free(buf); +} + + +int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res, + struct scan_info *info) +{ + size_t i = 0; + struct wpabuf *buf = NULL; + + if (!wpa_s->beacon_rep_data.token) + return 0; + + if (!wpa_s->current_bss) + goto out; + + /* If the measurement was aborted, don't report partial results */ + if (info->aborted) + goto out; + + wpa_printf(MSG_DEBUG, "RRM: TSF BSSID: " MACSTR " current BSS: " MACSTR, + MAC2STR(info->scan_start_tsf_bssid), + MAC2STR(wpa_s->current_bss->bssid)); + if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && + os_memcmp(info->scan_start_tsf_bssid, wpa_s->current_bss->bssid, + ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, + "RRM: Ignore scan results due to mismatching TSF BSSID"); + goto out; + } + + for (i = 0; i < scan_res->num; i++) { + struct wpa_bss *bss = + wpa_bss_get_bssid(wpa_s, scan_res->res[i]->bssid); + + if (!bss) + continue; + + if ((wpa_s->drv_rrm_flags & + WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && + os_memcmp(scan_res->res[i]->tsf_bssid, + wpa_s->current_bss->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, + "RRM: Ignore scan result for " MACSTR + " due to mismatching TSF BSSID" MACSTR, + MAC2STR(scan_res->res[i]->bssid), + MAC2STR(scan_res->res[i]->tsf_bssid)); + continue; + } + + /* + * Don't report results that were not received during the + * current measurement. + */ + if (!(wpa_s->drv_rrm_flags & + WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) { + struct os_reltime update_time, diff; + + /* For now, allow 8 ms older results due to some + * unknown issue with cfg80211 BSS table updates during + * a scan with the current BSS. + * TODO: Fix this more properly to avoid having to have + * this type of hacks in place. */ + calculate_update_time(&scan_res->fetch_time, + scan_res->res[i]->age, + &update_time); + os_reltime_sub(&wpa_s->beacon_rep_scan, + &update_time, &diff); + if (os_reltime_before(&update_time, + &wpa_s->beacon_rep_scan) && + (diff.sec || diff.usec >= 8000)) { + wpa_printf(MSG_DEBUG, + "RRM: Ignore scan result for " MACSTR + " due to old update (age(ms) %u, calculated age %u.%06u seconds)", + MAC2STR(scan_res->res[i]->bssid), + scan_res->res[i]->age, + (unsigned int) diff.sec, + (unsigned int) diff.usec); + continue; + } + } else if (info->scan_start_tsf > + scan_res->res[i]->parent_tsf) { + continue; + } + + if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf, + scan_res->res[i]->parent_tsf) < 0) + break; + } + + if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf)) + goto out; + + wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf); + + wpas_rrm_send_msr_report(wpa_s, buf); + wpabuf_free(buf); + +out: + wpas_clear_beacon_rep_data(wpa_s); + return 1; +} + + +void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s) +{ + struct beacon_rep_data *data = &wpa_s->beacon_rep_data; + + eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL); + bitfield_free(data->eids); + os_free(data->scan_params.freqs); + os_memset(data, 0, sizeof(*data)); +} diff --git a/contrib/wpa/wpa_supplicant/scan.c b/contrib/wpa/wpa_supplicant/scan.c index fb8ebdf2ecc1..7abb028dd344 100644 --- a/contrib/wpa/wpa_supplicant/scan.c +++ b/contrib/wpa/wpa_supplicant/scan.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Scanning - * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -117,9 +117,19 @@ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s) static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { + int min_temp_disabled = 0; + while (ssid) { - if (!wpas_network_disabled(wpa_s, ssid)) - break; + if (!wpas_network_disabled(wpa_s, ssid)) { + int temp_disabled = wpas_temp_disabled(wpa_s, ssid); + + if (temp_disabled <= 0) + break; + + if (!min_temp_disabled || + temp_disabled < min_temp_disabled) + min_temp_disabled = temp_disabled; + } ssid = ssid->next; } @@ -128,7 +138,7 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached " "end of scan list - go back to beginning"); wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; - wpa_supplicant_req_scan(wpa_s, 0, 0); + wpa_supplicant_req_scan(wpa_s, min_temp_disabled, 0); return; } if (ssid->next) { @@ -176,10 +186,22 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) params->only_new_results = 1; } ret = wpa_drv_scan(wpa_s, params); + /* + * Store the obtained vendor scan cookie (if any) in wpa_s context. + * The current design is to allow only one scan request on each + * interface, hence having this scan cookie stored in wpa_s context is + * fine for now. + * + * Revisit this logic if concurrent scan operations per interface + * is supported. + */ + if (ret == 0) + wpa_s->curr_scan_cookie = params->scan_cookie; wpa_scan_free_params(params); work->ctx = NULL; if (ret) { - int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ; + int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ && + !wpa_s->beacon_rep_data.token; if (wpa_s->disconnected) retry = 0; @@ -197,7 +219,14 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) /* Restore scan_req since we will try to scan again */ wpa_s->scan_req = wpa_s->last_scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); + } else if (wpa_s->scan_res_handler) { + /* Clear the scan_res_handler */ + wpa_s->scan_res_handler = NULL; } + + if (wpa_s->beacon_rep_data.token) + wpas_rrm_refuse_request(wpa_s); + return; } @@ -426,6 +455,33 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_MBO +static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s, + struct wpabuf **ie) +{ + if (wpabuf_resize(ie, 5)) { + wpa_printf(MSG_DEBUG, + "Failed to allocate space for FILS Request Parameters element"); + return; + } + + /* FILS Request Parameters element */ + wpabuf_put_u8(*ie, WLAN_EID_EXTENSION); + wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */ + wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS); + /* Parameter control bitmap */ + wpabuf_put_u8(*ie, 0); + /* Max Channel Time field - contains the value of MaxChannelTime + * parameter of the MLME-SCAN.request primitive represented in units of + * TUs, as an unsigned integer. A Max Channel Time field value of 255 + * is used to indicate any duration of more than 254 TUs, or an + * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178) + */ + wpabuf_put_u8(*ie, 255); +} +#endif /* CONFIG_MBO */ + + void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *default_ies = NULL; @@ -447,8 +503,10 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) wpabuf_put_data(default_ies, ext_capab, ext_capab_len); #ifdef CONFIG_MBO - /* Send cellular capabilities for potential MBO STAs */ - if (wpabuf_resize(&default_ies, 9) == 0) + if (wpa_s->enable_oce & OCE_STA) + wpas_fils_req_param_add_max_channel(wpa_s, &default_ies); + /* Send MBO and OCE capabilities */ + if (wpabuf_resize(&default_ies, 12) == 0) wpas_mbo_scan_ie(wpa_s, default_ies); #endif /* CONFIG_MBO */ @@ -488,6 +546,11 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) wpas_add_interworking_elements(wpa_s, extra_ie); #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_MBO + if (wpa_s->enable_oce & OCE_STA) + wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie); +#endif /* CONFIG_MBO */ + #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s, &req_type); @@ -518,8 +581,8 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) #endif /* CONFIG_WPS */ #ifdef CONFIG_HS20 - if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0) - wpas_hs20_add_indication(extra_ie, -1); + if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0) + wpas_hs20_add_indication(extra_ie, -1, 0); #endif /* CONFIG_HS20 */ #ifdef CONFIG_FST @@ -529,8 +592,8 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) #endif /* CONFIG_FST */ #ifdef CONFIG_MBO - /* Send cellular capabilities for potential MBO STAs */ - if (wpabuf_resize(&extra_ie, 9) == 0) + /* Send MBO and OCE capabilities */ + if (wpabuf_resize(&extra_ie, 12) == 0) wpas_mbo_scan_ie(wpa_s, extra_ie); #endif /* CONFIG_MBO */ @@ -614,6 +677,87 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, } +static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params, + size_t max_ssids, const u8 *ssid, size_t ssid_len) +{ + unsigned int j; + + for (j = 0; j < params->num_ssids; j++) { + if (params->ssids[j].ssid_len == ssid_len && + params->ssids[j].ssid && + os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0) + return; /* already in the list */ + } + + if (params->num_ssids + 1 > max_ssids) { + wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request"); + return; + } + + wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s", + wpa_ssid_txt(ssid, ssid_len)); + + params->ssids[params->num_ssids].ssid = ssid; + params->ssids[params->num_ssids].ssid_len = ssid_len; + params->num_ssids++; +} + + +static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params, + struct wpa_ssid *ssid, size_t max_ssids) +{ +#ifdef CONFIG_OWE + struct wpa_bss *bss; + + if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE)) + return; + + wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + const u8 *owe, *pos, *end; + const u8 *owe_ssid; + size_t owe_ssid_len; + + if (bss->ssid_len != ssid->ssid_len || + os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0) + continue; + + owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); + if (!owe || owe[1] < 4) + continue; + + pos = owe + 6; + end = owe + 2 + owe[1]; + + /* Must include BSSID and ssid_len */ + if (end - pos < ETH_ALEN + 1) + return; + + /* Skip BSSID */ + pos += ETH_ALEN; + owe_ssid_len = *pos++; + owe_ssid = pos; + + if ((size_t) (end - pos) < owe_ssid_len || + owe_ssid_len > SSID_MAX_LEN) + return; + + wpa_printf(MSG_DEBUG, + "OWE: scan_ssids: transition mode OWE ssid=%s", + wpa_ssid_txt(owe_ssid, owe_ssid_len)); + + wpa_add_scan_ssid(wpa_s, params, max_ssids, + owe_ssid, owe_ssid_len); + return; + } +#endif /* CONFIG_OWE */ +} + + static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params, size_t max_ssids) @@ -628,33 +772,17 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids; for (i = 0; i < wpa_s->scan_id_count; i++) { - unsigned int j; - ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]); - if (!ssid || !ssid->scan_ssid) + if (!ssid) continue; - - for (j = 0; j < params->num_ssids; j++) { - if (params->ssids[j].ssid_len == ssid->ssid_len && - params->ssids[j].ssid && - os_memcmp(params->ssids[j].ssid, ssid->ssid, - ssid->ssid_len) == 0) - break; - } - if (j < params->num_ssids) - continue; /* already in the list */ - - if (params->num_ssids + 1 > max_ssids) { - wpa_printf(MSG_DEBUG, - "Over max scan SSIDs for manual request"); - break; - } - - wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - params->ssids[params->num_ssids].ssid = ssid->ssid; - params->ssids[params->num_ssids].ssid_len = ssid->ssid_len; - params->num_ssids++; + if (ssid->scan_ssid) + wpa_add_scan_ssid(wpa_s, params, max_ssids, + ssid->ssid, ssid->ssid_len); + /* + * Also add the SSID of the OWE BSS, to allow discovery of + * transition mode APs more quickly. + */ + wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids); } wpa_s->scan_id_count = 0; @@ -703,10 +831,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) size_t max_ssids; int connect_without_scan = 0; - if (wpa_s->pno || wpa_s->pno_sched_pending) { - wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress"); - return; - } + wpa_s->ignore_post_flush_scan_res = 0; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); @@ -768,6 +893,21 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) return; } + /* + * Don't cancel the scan based on ongoing PNO; defer it. Some scans are + * used for changing modes inside wpa_supplicant (roaming, + * auto-reconnect, etc). Discarding the scan might hurt these processes. + * The normal use case for PNO is to suspend the host immediately after + * starting PNO, so the periodic 100 ms attempts to run the scan do not + * normally happen in practice multiple times, i.e., this is simply + * restarting scanning once the host is woken up and PNO stopped. + */ + if (wpa_s->pno || wpa_s->pno_sched_pending) { + wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress"); + wpa_supplicant_req_scan(wpa_s, 0, 100000); + return; + } + if (wpa_s->conf->ap_scan == 2) max_ssids = 1; else { @@ -909,6 +1049,17 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) if (params.num_ssids + 1 >= max_ssids) break; } + + if (!wpas_network_disabled(wpa_s, ssid)) { + /* + * Also add the SSID of the OWE BSS, to allow + * discovery of transition mode APs more + * quickly. + */ + wpa_add_owe_scan_ssid(wpa_s, ¶ms, ssid, + max_ssids); + } + ssid = ssid->next; if (ssid == start) break; @@ -995,6 +1146,13 @@ ssid_list_set: wpa_s->manual_scan_freqs = NULL; } + if (params.freqs == NULL && wpa_s->select_network_scan_freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Limit select_network scan to specified channels"); + params.freqs = wpa_s->select_network_scan_freqs; + wpa_s->select_network_scan_freqs = NULL; + } + if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); @@ -1029,6 +1187,11 @@ ssid_list_set: } } +#ifdef CONFIG_MBO + if (wpa_s->enable_oce & OCE_STA) + params.oce_scan = 1; +#endif /* CONFIG_MBO */ + params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); if (extra_ie) { @@ -1047,7 +1210,8 @@ ssid_list_set: } #endif /* CONFIG_P2P */ - if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) { + 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; @@ -1225,6 +1389,26 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, } +static void +wpa_scan_set_relative_rssi_params(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params) +{ + if (wpa_s->wpa_state != WPA_COMPLETED || + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI) || + wpa_s->srp.relative_rssi_set == 0) + return; + + params->relative_rssi_set = 1; + params->relative_rssi = wpa_s->srp.relative_rssi; + + if (wpa_s->srp.relative_adjust_rssi == 0) + return; + + params->relative_adjust_band = wpa_s->srp.relative_adjust_band; + params->relative_adjust_rssi = wpa_s->srp.relative_adjust_rssi; +} + + /** * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan * @wpa_s: Pointer to wpa_supplicant data @@ -1417,6 +1601,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) int_array_concat(¶ms.freqs, wpa_s->conf->freq_list); } +#ifdef CONFIG_MBO + if (wpa_s->enable_oce & OCE_STA) + params.oce_scan = 1; +#endif /* CONFIG_MBO */ + scan_params = ¶ms; scan: @@ -1458,18 +1647,24 @@ scan: params.sched_scan_plans_num = 1; } + params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay; + if (ssid || !wpa_s->first_sched_scan) { wpa_dbg(wpa_s, MSG_DEBUG, - "Starting sched scan: interval %u timeout %d", + "Starting sched scan after %u seconds: interval %u timeout %d", + params.sched_scan_start_delay, params.sched_scan_plans[0].interval, wpa_s->sched_scan_timeout); } else { - wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan (no timeout)"); + wpa_dbg(wpa_s, MSG_DEBUG, + "Starting sched scan after %u seconds (no timeout)", + params.sched_scan_start_delay); } wpa_setband_scan_freqs(wpa_s, scan_params); - if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) { + 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; @@ -1478,6 +1673,8 @@ 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); @@ -1618,7 +1815,13 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) */ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) { - return get_ie((const u8 *) (res + 1), res->ie_len, ie); + size_t ie_len = res->ie_len; + + /* Use the Beacon frame IEs if res->ie_len is not available */ + if (!ie_len) + ie_len = res->beacon_ie_len; + + return get_ie((const u8 *) (res + 1), ie_len, ie); } @@ -1735,10 +1938,12 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, * 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. 30 is chosen here as a - * conservative value. + * 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 30 +#define GREAT_SNR 25 #define IS_5GHZ(n) (n > 4000) @@ -1786,10 +1991,13 @@ static int wpa_scan_result_compar(const void *a, const void *b) } /* if SNR is close, decide by max rate or frequency band */ + if (snr_a && snr_b && abs(snr_b - snr_a) < 7) { + if (wa->est_throughput != wb->est_throughput) + return (int) wb->est_throughput - + (int) wa->est_throughput; + } if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) || (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { - if (wa->est_throughput != wb->est_throughput) - return wb->est_throughput - wa->est_throughput; if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq)) return IS_5GHZ(wa->freq) ? -1 : 1; } @@ -2177,10 +2385,22 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_WPS */ - qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), - compar); + if (scan_res->res) { + qsort(scan_res->res, scan_res->num, + sizeof(struct wpa_scan_res *), compar); + } dump_scan_res(scan_res); + if (wpa_s->ignore_post_flush_scan_res) { + /* FLUSH command aborted an ongoing scan and these are the + * results from the aborted scan. Do not process the results to + * maintain flushed state. */ + wpa_dbg(wpa_s, MSG_DEBUG, + "Do not update BSS table based on pending post-FLUSH scan results"); + wpa_s->ignore_post_flush_scan_res = 0; + return scan_res; + } + wpa_bss_update_start(wpa_s); for (i = 0; i < scan_res->num; i++) wpa_bss_update_scan_res(wpa_s, scan_res->res[i], @@ -2262,11 +2482,10 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) for (i = 0; i < src->num_ssids; i++) { if (src->ssids[i].ssid) { - n = os_malloc(src->ssids[i].ssid_len); + n = os_memdup(src->ssids[i].ssid, + src->ssids[i].ssid_len); if (n == NULL) goto failed; - os_memcpy(n, src->ssids[i].ssid, - src->ssids[i].ssid_len); params->ssids[i].ssid = n; params->ssids[i].ssid_len = src->ssids[i].ssid_len; } @@ -2274,30 +2493,26 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->num_ssids = src->num_ssids; if (src->extra_ies) { - n = os_malloc(src->extra_ies_len); + n = os_memdup(src->extra_ies, src->extra_ies_len); if (n == NULL) goto failed; - os_memcpy(n, src->extra_ies, src->extra_ies_len); params->extra_ies = n; params->extra_ies_len = src->extra_ies_len; } if (src->freqs) { int len = int_array_len(src->freqs); - params->freqs = os_malloc((len + 1) * sizeof(int)); + params->freqs = os_memdup(src->freqs, (len + 1) * sizeof(int)); if (params->freqs == NULL) goto failed; - os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int)); } if (src->filter_ssids) { - params->filter_ssids = os_malloc(sizeof(*params->filter_ssids) * + params->filter_ssids = os_memdup(src->filter_ssids, + sizeof(*params->filter_ssids) * src->num_filter_ssids); if (params->filter_ssids == NULL) goto failed; - os_memcpy(params->filter_ssids, src->filter_ssids, - sizeof(*params->filter_ssids) * - src->num_filter_ssids); params->num_filter_ssids = src->num_filter_ssids; } @@ -2305,17 +2520,18 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->p2p_probe = src->p2p_probe; params->only_new_results = src->only_new_results; params->low_priority = src->low_priority; + params->duration = src->duration; + params->duration_mandatory = src->duration_mandatory; + params->oce_scan = src->oce_scan; if (src->sched_scan_plans_num > 0) { params->sched_scan_plans = - os_malloc(sizeof(*src->sched_scan_plans) * + os_memdup(src->sched_scan_plans, + sizeof(*src->sched_scan_plans) * src->sched_scan_plans_num); if (!params->sched_scan_plans) goto failed; - os_memcpy(params->sched_scan_plans, src->sched_scan_plans, - sizeof(*src->sched_scan_plans) * - src->sched_scan_plans_num); params->sched_scan_plans_num = src->sched_scan_plans_num; } @@ -2340,13 +2556,16 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) if (src->bssid) { u8 *bssid; - bssid = os_malloc(ETH_ALEN); + bssid = os_memdup(src->bssid, ETH_ALEN); if (!bssid) goto failed; - os_memcpy(bssid, src->bssid, ETH_ALEN); params->bssid = bssid; } + params->relative_rssi_set = src->relative_rssi_set; + params->relative_rssi = src->relative_rssi; + params->relative_adjust_band = src->relative_adjust_band; + params->relative_adjust_rssi = src->relative_adjust_rssi; return params; failed: @@ -2404,7 +2623,7 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) return 0; if ((wpa_s->wpa_state > WPA_SCANNING) && - (wpa_s->wpa_state <= WPA_COMPLETED)) { + (wpa_s->wpa_state < WPA_COMPLETED)) { wpa_printf(MSG_ERROR, "PNO: In assoc process"); return -EAGAIN; } @@ -2511,12 +2730,15 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) params.sched_scan_plans_num = 1; } + params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay; + if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels"); params.freqs = wpa_s->manual_sched_scan_freqs; } - if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) { + 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; @@ -2524,6 +2746,8 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) } } + wpa_scan_set_relative_rssi_params(wpa_s, ¶ms); + ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms); os_free(params.filter_ssids); if (ret == 0) @@ -2583,6 +2807,13 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, { u8 *tmp = NULL; + if ((wpa_s->mac_addr_rand_supported & type) != type ) { + wpa_printf(MSG_INFO, + "scan: MAC randomization type %u != supported=%u", + type, wpa_s->mac_addr_rand_supported); + return -1; + } + wpas_mac_addr_rand_scan_clear(wpa_s, type); if (addr) { @@ -2614,18 +2845,20 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s) { - int scan_work = !!wpa_s->scan_work; - -#ifdef CONFIG_P2P - scan_work |= !!wpa_s->p2p_scan_work; -#endif /* CONFIG_P2P */ + struct wpa_radio_work *work; + struct wpa_radio *radio = wpa_s->radio; - if (scan_work && wpa_s->own_scan_running) { + dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) { + if (work->wpa_s != wpa_s || !work->started || + (os_strcmp(work->type, "scan") != 0 && + os_strcmp(work->type, "p2p-scan") != 0)) + continue; wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan"); - return wpa_drv_abort_scan(wpa_s); + return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie); } - return 0; + wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort"); + return -1; } diff --git a/contrib/wpa/wpa_supplicant/sme.c b/contrib/wpa/wpa_supplicant/sme.c index 61fd3b24549c..17a984d1a17d 100644 --- a/contrib/wpa/wpa_supplicant/sme.c +++ b/contrib/wpa/wpa_supplicant/sme.c @@ -12,9 +12,11 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/ocv.h" #include "eapol_supp/eapol_supp_sm.h" #include "common/wpa_common.h" #include "common/sae.h" +#include "common/dpp.h" #include "rsn_supp/wpa.h" #include "rsn_supp/pmksa_cache.h" #include "config.h" @@ -56,7 +58,7 @@ static int index_within_array(const int *array, int idx) static int sme_set_sae_group(struct wpa_supplicant *wpa_s) { int *groups = wpa_s->conf->sae_groups; - int default_groups[] = { 19, 20, 21, 25, 26, 0 }; + int default_groups[] = { 19, 20, 21, 0 }; if (!groups || groups[0] <= 0) groups = default_groups; @@ -72,7 +74,7 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s) if (sae_set_group(&wpa_s->sme.sae, group) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d", wpa_s->sme.sae.group); - return 0; + return 0; } wpa_s->sme.sae_group_index++; } @@ -83,43 +85,77 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s) static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, - const u8 *bssid) + const u8 *bssid, int external, + int reuse) { struct wpabuf *buf; size_t len; + const char *password; + +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->sae_commit_override) { + wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override"); + buf = wpabuf_alloc(4 + wpabuf_len(wpa_s->sae_commit_override)); + if (!buf) + return NULL; + if (!external) { + wpabuf_put_le16(buf, 1); /* Transaction seq# */ + wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + } + wpabuf_put_buf(buf, wpa_s->sae_commit_override); + return buf; + } +#endif /* CONFIG_TESTING_OPTIONS */ - if (ssid->passphrase == NULL) { + password = ssid->sae_password; + if (!password) + password = ssid->passphrase; + if (!password) { wpa_printf(MSG_DEBUG, "SAE: No password available"); return NULL; } + if (reuse && wpa_s->sme.sae.tmp && + os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) { + wpa_printf(MSG_DEBUG, + "SAE: Reuse previously generated PWE on a retry with the same AP"); + goto reuse_data; + } if (sme_set_sae_group(wpa_s) < 0) { wpa_printf(MSG_DEBUG, "SAE: Failed to select group"); return NULL; } if (sae_prepare_commit(wpa_s->own_addr, bssid, - (u8 *) ssid->passphrase, - os_strlen(ssid->passphrase), + (u8 *) password, os_strlen(password), + ssid->sae_password_id, &wpa_s->sme.sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); return NULL; } + if (wpa_s->sme.sae.tmp) + os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN); +reuse_data: len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0; + if (ssid->sae_password_id) + len += 4 + os_strlen(ssid->sae_password_id); buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len); if (buf == NULL) return NULL; - - wpabuf_put_le16(buf, 1); /* Transaction seq# */ - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); - sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token); + if (!external) { + wpabuf_put_le16(buf, 1); /* Transaction seq# */ + wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + } + sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, + ssid->sae_password_id); return buf; } -static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s) +static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s, + int external) { struct wpabuf *buf; @@ -127,8 +163,10 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s) if (buf == NULL) return NULL; - wpabuf_put_le16(buf, 2); /* Transaction seq# */ - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + if (!external) { + wpabuf_put_le16(buf, 2); /* Transaction seq# */ + wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + } sae_write_confirm(&wpa_s->sme.sae, buf); return buf; @@ -187,6 +225,10 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s, if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT; + *pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE | + WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE | + WLAN_RRM_CAPS_BEACON_REPORT_TABLE; + if (wpa_s->lci) pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT; @@ -204,16 +246,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211R const u8 *ie; #endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) const u8 *md = NULL; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R || CONFIG_FILS */ int i, bssid_changed; struct wpabuf *resp = NULL; u8 ext_capab[18]; int ext_capab_len; int skip_auth; + u8 *wpa_ie; + size_t wpa_ie_len; #ifdef CONFIG_MBO - const u8 *mbo; + const u8 *mbo_ie; #endif /* CONFIG_MBO */ if (bss == NULL) { @@ -272,6 +316,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (!rsn) { wpa_dbg(wpa_s, MSG_DEBUG, "SAE enabled, but target BSS does not advertise RSN"); +#ifdef CONFIG_DPP + } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && + (ssid->key_mgmt & WPA_KEY_MGMT_DPP) && + (ied.key_mgmt & WPA_KEY_MGMT_DPP)) { + wpa_dbg(wpa_s, MSG_DEBUG, "Prefer DPP over SAE when both are enabled"); +#endif /* CONFIG_DPP */ } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && wpa_key_mgmt_sae(ied.key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg"); @@ -300,13 +350,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_bss_get_ie(bss, WLAN_EID_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt)) { int try_opportunistic; + const u8 *cache_id = NULL; + try_opportunistic = (ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching) && (ssid->proto & WPA_PROTO_RSN); +#ifdef CONFIG_FILS + if (wpa_key_mgmt_fils(ssid->key_mgmt)) + cache_id = wpa_bss_get_fils_cache_id(bss); +#endif /* CONFIG_FILS */ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, wpa_s->current_ssid, - try_opportunistic) == 0) + try_opportunistic, cache_id, + 0) == 0) eapol_sm_notify_pmkid_attempt(wpa_s->eapol); wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); if (wpa_supplicant_set_suites(wpa_s, bss, ssid, @@ -317,6 +374,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpas_connect_work_done(wpa_s); return; } +#ifdef CONFIG_HS20 + } else if (wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) && + (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) { + /* No PMKSA caching, but otherwise similar to RSN/WPA */ + wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, + wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len)) { + wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " + "key management and encryption suites"); + wpas_connect_work_done(wpa_s); + return; + } +#endif /* CONFIG_HS20 */ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { /* @@ -356,17 +427,45 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.assoc_req_ie_len = 0; } + /* In case the WPA vendor IE is used, it should be placed after all the + * non-vendor IEs, as the lower layer expects the IEs to be ordered as + * defined in the standard. Store the WPA IE so it can later be + * inserted at the correct location. + */ + wpa_ie = NULL; + wpa_ie_len = 0; + if (wpa_s->wpa_proto == WPA_PROTO_WPA) { + wpa_ie = os_memdup(wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + if (wpa_ie) { + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Storing WPA IE"); + + wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_s->sme.assoc_req_ie_len = 0; + } else { + wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed copy WPA IE"); + wpas_connect_work_done(wpa_s); + return; + } + } + #ifdef CONFIG_IEEE80211R ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) md = ie + 2; wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0); + if (md && (!wpa_key_mgmt_ft(ssid->key_mgmt) || + !wpa_key_mgmt_ft(wpa_s->key_mgmt))) + md = NULL; if (md) { /* Prepare for the next transition */ wpa_ft_prepare_auth_request(wpa_s->wpa, ie); } - if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) { + if (md) { + wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x", + md[0], md[1]); + if (wpa_s->sme.assoc_req_ie_len + 5 < sizeof(wpa_s->sme.assoc_req_ie)) { struct rsn_mdie *mdie; @@ -381,7 +480,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.assoc_req_ie_len += 5; } - if (wpa_s->sme.ft_used && + if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used && os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 && wpa_sm_has_ptk(wpa_s->wpa)) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT " @@ -440,20 +539,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, sme_auth_handle_rrm(wpa_s, bss); -#ifdef CONFIG_MBO - mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); - if (mbo) { - int len; - - len = wpas_mbo_supp_op_class_ie( - wpa_s, bss->freq, - wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, - sizeof(wpa_s->sme.assoc_req_ie) - - wpa_s->sme.assoc_req_ie_len); - if (len > 0) - wpa_s->sme.assoc_req_ie_len += len; - } -#endif /* CONFIG_MBO */ + wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie( + wpa_s, ssid, bss->freq, + wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len); if (params.p2p) wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); @@ -477,12 +566,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (is_hs20_network(wpa_s, ssid, bss)) { struct wpabuf *hs20; - hs20 = wpabuf_alloc(20); + hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN); if (hs20) { int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid); size_t len; - wpas_hs20_add_indication(hs20, pps_mo_id); + wpas_hs20_add_indication(hs20, pps_mo_id, + get_hs20_version(bss)); + wpas_hs20_add_roam_cons_sel(hs20, ssid); len = sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len; if (wpabuf_len(hs20) <= len) { @@ -496,6 +587,26 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_HS20 */ + if (wpa_ie) { + size_t len; + + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Reinsert WPA IE"); + + len = sizeof(wpa_s->sme.assoc_req_ie) - + wpa_s->sme.assoc_req_ie_len; + + if (len > wpa_ie_len) { + os_memcpy(wpa_s->sme.assoc_req_ie + + wpa_s->sme.assoc_req_ie_len, + wpa_ie, wpa_ie_len); + wpa_s->sme.assoc_req_ie_len += wpa_ie_len; + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Failed to add WPA IE"); + } + + os_free(wpa_ie); + } + if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) { struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]; size_t len; @@ -511,13 +622,16 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #ifdef CONFIG_MBO - if (mbo) { + mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); + if (mbo_ie) { int len; len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, sizeof(wpa_s->sme.assoc_req_ie) - - wpa_s->sme.assoc_req_ie_len); + wpa_s->sme.assoc_req_ie_len, + !!mbo_attr_from_mbo_ie(mbo_ie, + OCE_ATTR_ID_CAPA_IND)); if (len >= 0) wpa_s->sme.assoc_req_ie_len += len; } @@ -525,10 +639,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_SAE if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE && - pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0) - { + pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0, + NULL, + wpa_s->key_mgmt == WPA_KEY_MGMT_FT_SAE ? + WPA_KEY_MGMT_FT_SAE : + WPA_KEY_MGMT_SAE) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication"); + wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); params.auth_alg = WPA_AUTH_ALG_OPEN; wpa_s->sme.sae_pmksa_caching = 1; } @@ -536,19 +654,106 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) { if (start) resp = sme_auth_build_sae_commit(wpa_s, ssid, - bss->bssid); + bss->bssid, 0, + start == 2); else - resp = sme_auth_build_sae_confirm(wpa_s); + resp = sme_auth_build_sae_confirm(wpa_s, 0); if (resp == NULL) { wpas_connection_failed(wpa_s, bss->bssid); return; } - params.sae_data = wpabuf_head(resp); - params.sae_data_len = wpabuf_len(resp); + params.auth_data = wpabuf_head(resp); + params.auth_data_len = wpabuf_len(resp); wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED; } #endif /* CONFIG_SAE */ + old_ssid = wpa_s->current_ssid; + wpa_s->current_ssid = ssid; + wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + wpa_supplicant_initiate_eapol(wpa_s); + +#ifdef CONFIG_FILS + /* TODO: FILS operations can in some cases be done between different + * network_ctx (i.e., same credentials can be used with multiple + * networks). */ + if (params.auth_alg == WPA_AUTH_ALG_OPEN && + wpa_key_mgmt_fils(ssid->key_mgmt)) { + const u8 *indic; + u16 fils_info; + const u8 *realm, *username, *rrk; + size_t realm_len, username_len, rrk_len; + u16 next_seq_num; + + /* + * Check FILS Indication element (FILS Information field) bits + * indicating supported authentication algorithms against local + * configuration (ssid->fils_dh_group). Try to use FILS + * authentication only if the AP supports the combination in the + * network profile. */ + indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); + if (!indic || indic[1] < 2) { + wpa_printf(MSG_DEBUG, "SME: " MACSTR + " does not include FILS Indication element - cannot use FILS authentication with it", + MAC2STR(bss->bssid)); + goto no_fils; + } + + fils_info = WPA_GET_LE16(indic + 2); + if (ssid->fils_dh_group == 0 && !(fils_info & BIT(9))) { + wpa_printf(MSG_DEBUG, "SME: " MACSTR + " does not support FILS SK without PFS - cannot use FILS authentication with it", + MAC2STR(bss->bssid)); + goto no_fils; + } + if (ssid->fils_dh_group != 0 && !(fils_info & BIT(10))) { + wpa_printf(MSG_DEBUG, "SME: " MACSTR + " does not support FILS SK with PFS - cannot use FILS authentication with it", + MAC2STR(bss->bssid)); + goto no_fils; + } + + if (wpa_s->last_con_fail_realm && + eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, + &username, &username_len, + &realm, &realm_len, &next_seq_num, + &rrk, &rrk_len) == 0 && + realm && realm_len == wpa_s->last_con_fail_realm_len && + os_memcmp(realm, wpa_s->last_con_fail_realm, + realm_len) == 0) { + wpa_printf(MSG_DEBUG, + "SME: FILS authentication for this realm failed last time - try to regenerate ERP key hierarchy"); + goto no_fils; + } + + if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, + ssid, 0, + wpa_bss_get_fils_cache_id(bss), + 0) == 0) + wpa_printf(MSG_DEBUG, + "SME: Try to use FILS with PMKSA caching"); + resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md); + if (resp) { + int auth_alg; + + if (ssid->fils_dh_group) + wpa_printf(MSG_DEBUG, + "SME: Try to use FILS SK authentication with PFS (DH Group %u)", + ssid->fils_dh_group); + else + wpa_printf(MSG_DEBUG, + "SME: Try to use FILS SK authentication without PFS"); + auth_alg = ssid->fils_dh_group ? + WPA_AUTH_ALG_FILS_SK_PFS : WPA_AUTH_ALG_FILS; + params.auth_alg = auth_alg; + params.auth_data = wpabuf_head(resp); + params.auth_data_len = wpabuf_len(resp); + wpa_s->sme.auth_alg = auth_alg; + } + } +no_fils: +#endif /* CONFIG_FILS */ + wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); @@ -556,12 +761,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, " (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); wpa_clear_keys(wpa_s, bss->bssid); wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); - old_ssid = wpa_s->current_ssid; - wpa_s->current_ssid = ssid; - wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); - wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); @@ -650,6 +852,10 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit) return; } + /* 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); + sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1); } @@ -700,8 +906,150 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, #ifdef CONFIG_SAE +static int sme_external_auth_build_buf(struct wpabuf *buf, + struct wpabuf *params, + const u8 *sa, const u8 *da, + u16 auth_transaction, u16 seq_num) +{ + struct ieee80211_mgmt *resp; + + resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt, + u.auth.variable)); + + resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_AUTH << 4)); + os_memcpy(resp->da, da, ETH_ALEN); + os_memcpy(resp->sa, sa, ETH_ALEN); + os_memcpy(resp->bssid, da, ETH_ALEN); + resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE); + resp->seq_ctrl = host_to_le16(seq_num << 4); + resp->u.auth.auth_transaction = host_to_le16(auth_transaction); + resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); + if (params) + wpabuf_put_buf(buf, params); + + return 0; +} + + +static void sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, + const u8 *bssid, + struct wpa_ssid *ssid) +{ + struct wpabuf *resp, *buf; + + resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0); + if (!resp) + return; + + wpa_s->sme.sae.state = SAE_COMMITTED; + buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp)); + if (!buf) { + wpabuf_free(resp); + return; + } + + wpa_s->sme.seq_num++; + sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, + bssid, 1, wpa_s->sme.seq_num); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0); + wpabuf_free(resp); + wpabuf_free(buf); +} + + +static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s, + u16 status) +{ + struct external_auth params; + + os_memset(¶ms, 0, sizeof(params)); + params.status = status; + params.ssid = wpa_s->sme.ext_auth.ssid; + params.ssid_len = wpa_s->sme.ext_auth.ssid_len; + params.bssid = wpa_s->sme.ext_auth.bssid; + wpa_drv_send_external_auth_status(wpa_s, ¶ms); +} + + +static void sme_handle_external_auth_start(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + struct wpa_ssid *ssid; + size_t ssid_str_len = data->external_auth.ssid_len; + const u8 *ssid_str = data->external_auth.ssid; + + /* Get the SSID conf from the ssid string obtained */ + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (!wpas_network_disabled(wpa_s, ssid) && + ssid_str_len == ssid->ssid_len && + os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 && + (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))) + break; + } + if (ssid) + sme_external_auth_send_sae_commit(wpa_s, + data->external_auth.bssid, + ssid); + else + sme_send_external_auth_status(wpa_s, + WLAN_STATUS_UNSPECIFIED_FAILURE); +} + + +static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s, + const u8 *da) +{ + struct wpabuf *resp, *buf; + + resp = sme_auth_build_sae_confirm(wpa_s, 1); + if (!resp) { + wpa_printf(MSG_DEBUG, "SAE: Confirm message buf alloc failure"); + return; + } + + wpa_s->sme.sae.state = SAE_CONFIRMED; + buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp)); + if (!buf) { + wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure"); + wpabuf_free(resp); + return; + } + wpa_s->sme.seq_num++; + sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, + da, 2, wpa_s->sme.seq_num); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0); + wpabuf_free(resp); + wpabuf_free(buf); +} + + +void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) != + RSN_AUTH_KEY_MGMT_SAE) + return; + + if (data->external_auth.action == EXT_AUTH_START) { + os_memcpy(&wpa_s->sme.ext_auth, data, + sizeof(struct external_auth)); + wpa_s->sme.seq_num = 0; + wpa_s->sme.sae.state = SAE_NOTHING; + wpa_s->sme.sae.send_confirm = 0; + wpa_s->sme.sae_group_index = 0; + sme_handle_external_auth_start(wpa_s, data); + } else if (data->external_auth.action == EXT_AUTH_ABORT) { + /* Report failure to driver for the wrong trigger */ + sme_send_external_auth_status(wpa_s, + WLAN_STATUS_UNSPECIFIED_FAILURE); + } +} + + static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, - u16 status_code, const u8 *data, size_t len) + u16 status_code, const u8 *data, size_t len, + int external, const u8 *sa) { int *groups; @@ -711,8 +1059,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (auth_transaction == 1 && status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ && wpa_s->sme.sae.state == SAE_COMMITTED && - wpa_s->current_bss && wpa_s->current_ssid) { - int default_groups[] = { 19, 20, 21, 25, 26, 0 }; + (external || wpa_s->current_bss) && wpa_s->current_ssid) { + int default_groups[] = { 19, 20, 21, 0 }; u16 group; groups = wpa_s->conf->sae_groups; @@ -738,25 +1086,45 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpabuf_free(wpa_s->sme.sae_token); wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16), len - sizeof(le16)); - sme_send_authentication(wpa_s, wpa_s->current_bss, - wpa_s->current_ssid, 1); + if (!external) + sme_send_authentication(wpa_s, wpa_s->current_bss, + wpa_s->current_ssid, 2); + else + sme_external_auth_send_sae_commit( + wpa_s, wpa_s->sme.ext_auth.bssid, + wpa_s->current_ssid); return 0; } if (auth_transaction == 1 && status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && wpa_s->sme.sae.state == SAE_COMMITTED && - wpa_s->current_bss && wpa_s->current_ssid) { + (external || wpa_s->current_bss) && wpa_s->current_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported"); wpa_s->sme.sae_group_index++; if (sme_set_sae_group(wpa_s) < 0) return -1; /* no other groups enabled */ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group"); - sme_send_authentication(wpa_s, wpa_s->current_bss, - wpa_s->current_ssid, 1); + if (!external) + sme_send_authentication(wpa_s, wpa_s->current_bss, + wpa_s->current_ssid, 1); + else + sme_external_auth_send_sae_commit( + wpa_s, wpa_s->sme.ext_auth.bssid, + wpa_s->current_ssid); return 0; } + if (auth_transaction == 1 && + status_code == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) { + const u8 *bssid = sa ? sa : wpa_s->pending_bssid; + + wpa_msg(wpa_s, MSG_INFO, + WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER MACSTR, + MAC2STR(bssid)); + return -1; + } + if (status_code != WLAN_STATUS_SUCCESS) return -1; @@ -766,7 +1134,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, groups = wpa_s->conf->sae_groups; wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit"); - if (wpa_s->current_bss == NULL || + if ((!external && wpa_s->current_bss == NULL) || wpa_s->current_ssid == NULL) return -1; if (wpa_s->sme.sae.state != SAE_COMMITTED) @@ -791,8 +1159,11 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpabuf_free(wpa_s->sme.sae_token); wpa_s->sme.sae_token = NULL; - sme_send_authentication(wpa_s, wpa_s->current_bss, - wpa_s->current_ssid, 0); + if (!external) + sme_send_authentication(wpa_s, wpa_s->current_bss, + wpa_s->current_ssid, 0); + else + sme_external_auth_send_sae_confirm(wpa_s, sa); return 0; } else if (auth_transaction == 2) { wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm"); @@ -802,11 +1173,60 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, return -1; wpa_s->sme.sae.state = SAE_ACCEPTED; sae_clear_temp_data(&wpa_s->sme.sae); + + if (external) { + /* Report success to driver */ + sme_send_external_auth_status(wpa_s, + WLAN_STATUS_SUCCESS); + } + return 1; } return -1; } + + +void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, + const u8 *auth_frame, size_t len) +{ + const struct ieee80211_mgmt *header; + size_t auth_length; + + header = (const struct ieee80211_mgmt *) auth_frame; + auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth); + + if (len < auth_length) { + /* Notify failure to the driver */ + sme_send_external_auth_status(wpa_s, + WLAN_STATUS_UNSPECIFIED_FAILURE); + return; + } + + if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) { + int res; + + res = sme_sae_auth( + wpa_s, le_to_host16(header->u.auth.auth_transaction), + le_to_host16(header->u.auth.status_code), + header->u.auth.variable, + len - auth_length, 1, header->sa); + if (res < 0) { + /* Notify failure to the driver */ + sme_send_external_auth_status( + wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE); + return; + } + if (res != 1) + return; + + wpa_printf(MSG_DEBUG, + "SME: SAE completed - setting PMK for 4-way handshake"); + wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN, + wpa_s->sme.sae.pmkid, wpa_s->pending_bssid); + } +} + #endif /* CONFIG_SAE */ @@ -847,7 +1267,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) int res; res = sme_sae_auth(wpa_s, data->auth.auth_transaction, data->auth.status_code, data->auth.ies, - data->auth.ies_len); + data->auth.ies_len, 0, NULL); if (res < 0) { wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); @@ -875,12 +1295,19 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) } } wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR - " auth_type=%u auth_transaction=%u status_code=%u ie=%s", + " auth_type=%u auth_transaction=%u status_code=%u%s%s", MAC2STR(data->auth.peer), data->auth.auth_type, data->auth.auth_transaction, data->auth.status_code, - ie_txt); + ie_txt ? " ie=" : "", + ie_txt ? ie_txt : ""); os_free(ie_txt); +#ifdef CONFIG_FILS + if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS || + wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) + fils_connection_failure(wpa_s); +#endif /* CONFIG_FILS */ + if (data->auth.status_code != WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG || wpa_s->sme.auth_alg == data->auth.auth_type || @@ -916,9 +1343,17 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) #ifdef CONFIG_IEEE80211R if (data->auth.auth_type == WLAN_AUTH_FT) { + const u8 *ric_ies = NULL; + size_t ric_ies_len = 0; + + if (wpa_s->ric_ies) { + ric_ies = wpabuf_head(wpa_s->ric_ies); + ric_ies_len = wpabuf_len(wpa_s->ric_ies); + } if (wpa_ft_process_response(wpa_s->wpa, data->auth.ies, data->auth.ies_len, 0, - data->auth.peer, NULL, 0) < 0) { + data->auth.peer, + ric_ies, ric_ies_len) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT Authentication response processing failed"); wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" @@ -933,16 +1368,73 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_FILS + if (data->auth.auth_type == WLAN_AUTH_FILS_SK || + data->auth.auth_type == WLAN_AUTH_FILS_SK_PFS) { + u16 expect_auth_type; + + expect_auth_type = wpa_s->sme.auth_alg == + WPA_AUTH_ALG_FILS_SK_PFS ? WLAN_AUTH_FILS_SK_PFS : + WLAN_AUTH_FILS_SK; + if (data->auth.auth_type != expect_auth_type) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: FILS Authentication response used different auth alg (%u; expected %u)", + data->auth.auth_type, expect_auth_type); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" + MACSTR + " reason=%d locally_generated=1", + MAC2STR(wpa_s->pending_bssid), + WLAN_REASON_DEAUTH_LEAVING); + wpas_connection_failed(wpa_s, wpa_s->pending_bssid); + wpa_supplicant_mark_disassoc(wpa_s); + return; + } + + if (fils_process_auth(wpa_s->wpa, wpa_s->pending_bssid, + data->auth.ies, data->auth.ies_len) < 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: FILS Authentication response processing failed"); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" + MACSTR + " reason=%d locally_generated=1", + MAC2STR(wpa_s->pending_bssid), + WLAN_REASON_DEAUTH_LEAVING); + wpas_connection_failed(wpa_s, wpa_s->pending_bssid); + wpa_supplicant_mark_disassoc(wpa_s); + return; + } + } +#endif /* CONFIG_FILS */ + sme_associate(wpa_s, ssid->mode, data->auth.peer, data->auth.auth_type); } +#ifdef CONFIG_IEEE80211R +static void remove_ie(u8 *buf, size_t *len, u8 eid) +{ + u8 *pos, *next, *end; + + pos = (u8 *) get_ie(buf, *len, eid); + if (pos) { + next = pos + 2 + pos[1]; + end = buf + *len; + *len -= 2 + pos[1]; + os_memmove(pos, next, end - next); + } +} +#endif /* CONFIG_IEEE80211R */ + + void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, const u8 *bssid, u16 auth_type) { struct wpa_driver_associate_params params; struct ieee802_11_elems elems; +#ifdef CONFIG_FILS + u8 nonces[2 * FILS_NONCE_LEN]; +#endif /* CONFIG_FILS */ #ifdef CONFIG_HT_OVERRIDES struct ieee80211_ht_capabilities htcaps; struct ieee80211_ht_capabilities htcaps_mask; @@ -953,6 +1445,184 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, #endif /* CONFIG_VHT_OVERRIDES */ os_memset(¶ms, 0, sizeof(params)); + +#ifdef CONFIG_FILS + if (auth_type == WLAN_AUTH_FILS_SK || + auth_type == WLAN_AUTH_FILS_SK_PFS) { + struct wpabuf *buf; + const u8 *snonce, *anonce; + const unsigned int max_hlp = 20; + struct wpabuf *hlp[max_hlp]; + unsigned int i, num_hlp = 0; + struct fils_hlp_req *req; + + dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req, + list) { + hlp[num_hlp] = wpabuf_alloc(2 * ETH_ALEN + 6 + + wpabuf_len(req->pkt)); + if (!hlp[num_hlp]) + break; + wpabuf_put_data(hlp[num_hlp], req->dst, ETH_ALEN); + wpabuf_put_data(hlp[num_hlp], wpa_s->own_addr, + ETH_ALEN); + wpabuf_put_data(hlp[num_hlp], + "\xaa\xaa\x03\x00\x00\x00", 6); + wpabuf_put_buf(hlp[num_hlp], req->pkt); + num_hlp++; + if (num_hlp >= max_hlp) + break; + } + + buf = fils_build_assoc_req(wpa_s->wpa, ¶ms.fils_kek, + ¶ms.fils_kek_len, &snonce, + &anonce, + (const struct wpabuf **) hlp, + num_hlp); + for (i = 0; i < num_hlp; i++) + wpabuf_free(hlp[i]); + if (!buf) + return; + wpa_hexdump(MSG_DEBUG, "FILS: assoc_req before FILS elements", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) { + /* Remove RSNE and MDE to allow them to be overridden + * with FILS+FT specific values from + * fils_build_assoc_req(). */ + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RSN); + wpa_hexdump(MSG_DEBUG, + "FILS: assoc_req after RSNE removal", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_MOBILITY_DOMAIN); + wpa_hexdump(MSG_DEBUG, + "FILS: assoc_req after MDE removal", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + } +#endif /* CONFIG_IEEE80211R */ + /* TODO: Make wpa_s->sme.assoc_req_ie use dynamic allocation */ + if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(buf) > + sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_printf(MSG_ERROR, + "FILS: Not enough buffer room for own AssocReq elements"); + wpabuf_free(buf); + return; + } + os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + wpabuf_head(buf), wpabuf_len(buf)); + wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf); + wpabuf_free(buf); + wpa_hexdump(MSG_DEBUG, "FILS: assoc_req after FILS elements", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + + os_memcpy(nonces, snonce, FILS_NONCE_LEN); + os_memcpy(nonces + FILS_NONCE_LEN, anonce, FILS_NONCE_LEN); + params.fils_nonces = nonces; + params.fils_nonces_len = sizeof(nonces); + } +#endif /* CONFIG_FILS */ + +#ifdef CONFIG_OWE +#ifdef CONFIG_TESTING_OPTIONS + if (get_ie_ext(wpa_s->sme.assoc_req_ie, wpa_s->sme.assoc_req_ie_len, + WLAN_EID_EXT_OWE_DH_PARAM)) { + wpa_printf(MSG_INFO, "TESTING: Override OWE DH element"); + } else +#endif /* CONFIG_TESTING_OPTIONS */ + if (auth_type == WLAN_AUTH_OPEN && + wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) { + struct wpabuf *owe_ie; + u16 group; + + if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) { + group = wpa_s->current_ssid->owe_group; + } else if (wpa_s->assoc_status_code == + WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { + if (wpa_s->last_owe_group == 19) + group = 20; + else if (wpa_s->last_owe_group == 20) + group = 21; + else + group = OWE_DH_GROUP; + } else { + group = OWE_DH_GROUP; + } + + wpa_s->last_owe_group = group; + wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group); + owe_ie = owe_build_assoc_req(wpa_s->wpa, group); + if (!owe_ie) { + wpa_printf(MSG_ERROR, + "OWE: Failed to build IE for Association Request frame"); + return; + } + if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(owe_ie) > + sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_printf(MSG_ERROR, + "OWE: Not enough buffer room for own Association Request frame elements"); + wpabuf_free(owe_ie); + return; + } + os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + wpabuf_head(owe_ie), wpabuf_len(owe_ie)); + wpa_s->sme.assoc_req_ie_len += wpabuf_len(owe_ie); + wpabuf_free(owe_ie); + } +#endif /* CONFIG_OWE */ + +#ifdef CONFIG_DPP2 + if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid && + wpa_s->current_ssid->dpp_netaccesskey) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + + dpp_pfs_free(wpa_s->dpp_pfs); + wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey, + ssid->dpp_netaccesskey_len); + if (!wpa_s->dpp_pfs) { + wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS"); + /* Try to continue without PFS */ + goto pfs_fail; + } + if (wpa_s->sme.assoc_req_ie_len + + wpabuf_len(wpa_s->dpp_pfs->ie) > + sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_printf(MSG_ERROR, + "DPP: Not enough buffer room for own Association Request frame elements"); + dpp_pfs_free(wpa_s->dpp_pfs); + wpa_s->dpp_pfs = NULL; + goto pfs_fail; + } + os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + wpabuf_head(wpa_s->dpp_pfs->ie), + wpabuf_len(wpa_s->dpp_pfs->ie)); + wpa_s->sme.assoc_req_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie); + } +pfs_fail: +#endif /* CONFIG_DPP2 */ + + if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) { + size_t multi_ap_ie_len; + + multi_ap_ie_len = add_multi_ap_ie( + wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + sizeof(wpa_s->sme.assoc_req_ie) - + wpa_s->sme.assoc_req_ie_len, + MULTI_AP_BACKHAUL_STA); + if (multi_ap_ie_len == 0) { + wpa_printf(MSG_ERROR, + "Multi-AP: Failed to build Multi-AP IE"); + return; + } + wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len; + } + params.bssid = bssid; params.ssid = wpa_s->sme.ssid; params.ssid_len = wpa_s->sme.ssid_len; @@ -962,8 +1632,11 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs", + params.wpa_ie, params.wpa_ie_len); params.pairwise_suite = wpa_s->pairwise_cipher; params.group_suite = wpa_s->group_cipher; + params.mgmt_group_suite = wpa_s->mgmt_group_cipher; params.key_mgmt_suite = wpa_s->key_mgmt; params.wpa_proto = wpa_s->wpa_proto; #ifdef CONFIG_HT_OVERRIDES @@ -981,9 +1654,85 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ #ifdef CONFIG_IEEE80211R - if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { + if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies && + get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len, + WLAN_EID_RIC_DATA)) { + /* There seems to be a pretty inconvenient bug in the Linux + * kernel IE splitting functionality when RIC is used. For now, + * skip correct behavior in IE construction here (i.e., drop the + * additional non-FT-specific IEs) to avoid kernel issues. This + * is fine since RIC is used only for testing purposes in the + * current implementation. */ + wpa_printf(MSG_INFO, + "SME: Linux kernel workaround - do not try to include additional IEs with RIC"); params.wpa_ie = wpa_s->sme.ft_ies; params.wpa_ie_len = wpa_s->sme.ft_ies_len; + } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { + const u8 *rm_en, *pos, *end; + size_t rm_en_len = 0; + u8 *rm_en_dup = NULL, *wpos; + + /* Remove RSNE, MDE, FTE to allow them to be overridden with + * FT specific values */ + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RSN); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_MOBILITY_DOMAIN); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_FAST_BSS_TRANSITION); + rm_en = get_ie(wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RRM_ENABLED_CAPABILITIES); + if (rm_en) { + /* Need to remove RM Enabled Capabilities element as + * well temporarily, so that it can be placed between + * RSNE and MDE. */ + rm_en_len = 2 + rm_en[1]; + rm_en_dup = os_memdup(rm_en, rm_en_len); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RRM_ENABLED_CAPABILITIES); + } + wpa_hexdump(MSG_DEBUG, + "SME: Association Request IEs after FT IE removal", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len + + rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_printf(MSG_ERROR, + "SME: Not enough buffer room for FT IEs in Association Request frame"); + os_free(rm_en_dup); + return; + } + + os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len + + rm_en_len, + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + pos = wpa_s->sme.ft_ies; + end = pos + wpa_s->sme.ft_ies_len; + wpos = wpa_s->sme.assoc_req_ie; + if (*pos == WLAN_EID_RSN) { + os_memcpy(wpos, pos, 2 + pos[1]); + wpos += 2 + pos[1]; + pos += 2 + pos[1]; + } + if (rm_en_dup) { + os_memcpy(wpos, rm_en_dup, rm_en_len); + wpos += rm_en_len; + os_free(rm_en_dup); + } + os_memcpy(wpos, pos, end - pos); + wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len + + rm_en_len; + params.wpa_ie = wpa_s->sme.assoc_req_ie; + params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_hexdump(MSG_DEBUG, + "SME: Association Request IEs after FT override", + params.wpa_ie, params.wpa_ie_len); } #endif /* CONFIG_IEEE80211R */ params.mode = mode; @@ -1038,6 +1787,14 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s, NULL); + +#ifdef CONFIG_TESTING_OPTIONS + wpabuf_free(wpa_s->last_assoc_req_wpa_ie); + wpa_s->last_assoc_req_wpa_ie = NULL; + if (params.wpa_ie) + wpa_s->last_assoc_req_wpa_ie = + wpabuf_alloc_copy(params.wpa_ie, params.wpa_ie_len); +#endif /* CONFIG_TESTING_OPTIONS */ } @@ -1056,10 +1813,9 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN); wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len); os_free(wpa_s->sme.ft_ies); - wpa_s->sme.ft_ies = os_malloc(ies_len); + wpa_s->sme.ft_ies = os_memdup(ies, ies_len); if (wpa_s->sme.ft_ies == NULL) return -1; - os_memcpy(wpa_s->sme.ft_ies, ies, ies_len); wpa_s->sme.ft_ies_len = ies_len; return 0; } @@ -1226,20 +1982,17 @@ void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s) sae_clear_data(&wpa_s->sme.sae); #endif /* CONFIG_SAE */ #ifdef CONFIG_IEEE80211R - if (wpa_s->sme.ft_ies) + if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used) sme_update_ft_ies(wpa_s, NULL, NULL, 0); #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + sme_stop_sa_query(wpa_s); +#endif /* CONFIG_IEEE80211W */ } void sme_deinit(struct wpa_supplicant *wpa_s) { - os_free(wpa_s->sme.ft_ies); - wpa_s->sme.ft_ies = NULL; - wpa_s->sme.ft_ies_len = 0; -#ifdef CONFIG_IEEE80211W - sme_stop_sa_query(wpa_s); -#endif /* CONFIG_IEEE80211W */ sme_clear_on_disassoc(wpa_s); eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL); @@ -1533,6 +2286,7 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) static const unsigned int sa_query_max_timeout = 1000; static const unsigned int sa_query_retry_timeout = 201; +static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */ static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s) { @@ -1556,7 +2310,9 @@ static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s) static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s, const u8 *trans_id) { - u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN]; + u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN]; + u8 req_len = 2 + WLAN_SA_QUERY_TR_ID_LEN; + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to " MACSTR, MAC2STR(wpa_s->bssid)); wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID", @@ -1564,9 +2320,27 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s, req[0] = WLAN_ACTION_SA_QUERY; req[1] = WLAN_SA_QUERY_REQUEST; os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN); + +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(wpa_s->wpa)) { + struct wpa_channel_info ci; + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info for OCI element in SA Query Request frame"); + return; + } + + if (ocv_insert_extended_oci(&ci, req + req_len) < 0) + return; + + req_len += OCV_OCI_EXTENDED_LEN; + } +#endif /* CONFIG_OCV */ + if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, - req, sizeof(req), 0) < 0) + req, req_len, 0) < 0) wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query " "Request"); } @@ -1623,6 +2397,8 @@ static void sme_start_sa_query(struct wpa_supplicant *wpa_s) static void sme_stop_sa_query(struct wpa_supplicant *wpa_s) { + if (wpa_s->sme.sa_query_trans_id) + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Stop SA Query"); eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL); os_free(wpa_s->sme.sa_query_trans_id); wpa_s->sme.sa_query_trans_id = NULL; @@ -1661,15 +2437,74 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, } -void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, - const u8 *data, size_t len) +void sme_event_ch_switch(struct wpa_supplicant *wpa_s) +{ + unsigned int usec; + u32 _rand; + + if (wpa_s->wpa_state != WPA_COMPLETED || + !wpa_sm_ocv_enabled(wpa_s->wpa)) + return; + + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Channel switch completed - trigger new SA Query to verify new operating channel"); + sme_stop_sa_query(wpa_s); + + if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) + _rand = os_random(); + usec = _rand % (sa_query_ch_switch_max_delay + 1); + eloop_register_timeout(0, usec, sme_sa_query_timer, wpa_s, NULL); +} + + +static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s, + const u8 *sa, const u8 *data, + size_t len) +{ + u8 resp[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN]; + u8 resp_len = 2 + WLAN_SA_QUERY_TR_ID_LEN; + + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Response to " + MACSTR, MAC2STR(wpa_s->bssid)); + + resp[0] = WLAN_ACTION_SA_QUERY; + resp[1] = WLAN_SA_QUERY_RESPONSE; + os_memcpy(resp + 2, data + 1, WLAN_SA_QUERY_TR_ID_LEN); + +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(wpa_s->wpa)) { + struct wpa_channel_info ci; + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info for OCI element in SA Query Response frame"); + return; + } + + if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0) + return; + + resp_len += OCV_OCI_EXTENDED_LEN; + } +#endif /* CONFIG_OCV */ + + if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + resp, resp_len, 0) < 0) + wpa_msg(wpa_s, MSG_INFO, + "SME: Failed to send SA Query Response"); +} + + +static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s, + const u8 *sa, const u8 *data, + size_t len) { int i; - if (wpa_s->sme.sa_query_trans_id == NULL || - len < 1 + WLAN_SA_QUERY_TR_ID_LEN || - data[0] != WLAN_SA_QUERY_RESPONSE) + if (!wpa_s->sme.sa_query_trans_id) return; + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from " MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]); @@ -1694,4 +2529,48 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, sme_stop_sa_query(wpa_s); } + +void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, + const u8 *data, size_t len) +{ + if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN) + return; + + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from " + MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]); + +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(wpa_s->wpa)) { + struct ieee802_11_elems elems; + struct wpa_channel_info ci; + + if (ieee802_11_parse_elems(data + 1 + WLAN_SA_QUERY_TR_ID_LEN, + len - 1 - WLAN_SA_QUERY_TR_ID_LEN, + &elems, 1) == ParseFailed) { + wpa_printf(MSG_DEBUG, + "SA Query: Failed to parse elements"); + return; + } + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info to validate received OCI in SA Query Action frame"); + return; + } + + if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, + channel_width_to_int(ci.chanwidth), + ci.seg1_idx) != 0) { + wpa_printf(MSG_WARNING, "%s", ocv_errorstr); + return; + } + } +#endif /* CONFIG_OCV */ + + if (data[0] == WLAN_SA_QUERY_REQUEST) + sme_process_sa_query_request(wpa_s, sa, data, len); + else if (data[0] == WLAN_SA_QUERY_RESPONSE) + sme_process_sa_query_response(wpa_s, sa, data, len); +} + #endif /* CONFIG_IEEE80211W */ diff --git a/contrib/wpa/wpa_supplicant/sme.h b/contrib/wpa/wpa_supplicant/sme.h index fd5c3b4e1ed8..1a7f9e8320c7 100644 --- a/contrib/wpa/wpa_supplicant/sme.h +++ b/contrib/wpa/wpa_supplicant/sme.h @@ -28,6 +28,7 @@ void sme_event_disassoc(struct wpa_supplicant *wpa_s, struct disassoc_info *info); void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *da, u16 reason_code); +void sme_event_ch_switch(struct wpa_supplicant *wpa_s); void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *data, size_t len); void sme_state_changed(struct wpa_supplicant *wpa_s); @@ -38,6 +39,10 @@ void sme_deinit(struct wpa_supplicant *wpa_s); int sme_proc_obss_scan(struct wpa_supplicant *wpa_s); void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable); +void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, + union wpa_event_data *data); +void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, + const u8 *auth_frame, size_t len); #else /* CONFIG_SME */ @@ -85,6 +90,10 @@ static inline void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, { } +static inline void sme_event_ch_switch(struct wpa_supplicant *wpa_s) +{ +} + static inline void sme_state_changed(struct wpa_supplicant *wpa_s) { } @@ -113,6 +122,16 @@ static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, { } +static inline void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ +} + +static inline void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, + const u8 *auth_frame, size_t len) +{ +} + #endif /* CONFIG_SME */ #endif /* SME_H */ diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in index bc5d49af8655..75a37a8cdbd3 100644 --- a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in +++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in @@ -5,9 +5,9 @@ Wants=network.target [Service] Type=dbus -BusName=@DBUS_INTERFACE@ +BusName=fi.w1.wpa_supplicant1 ExecStart=@BINDIR@/wpa_supplicant -u [Install] WantedBy=multi-user.target -Alias=dbus-@DBUS_INTERFACE@.service +Alias=dbus-fi.w1.wpa_supplicant1.service diff --git a/contrib/wpa/wpa_supplicant/utils/log2pcap.py b/contrib/wpa/wpa_supplicant/utils/log2pcap.py index 65e2fa109cbb..141aecbe5178 100755 --- a/contrib/wpa/wpa_supplicant/utils/log2pcap.py +++ b/contrib/wpa/wpa_supplicant/utils/log2pcap.py @@ -28,7 +28,7 @@ if __name__ == "__main__": input = sys.argv[1] pcap = sys.argv[2] except IndexError: - print "Usage: %s <log file> <pcap file>" % sys.argv[0] + print("Usage: %s <log file> <pcap file>" % sys.argv[0]) sys.exit(2) input_file = open(input, 'r') diff --git a/contrib/wpa/wpa_supplicant/wifi_display.c b/contrib/wpa/wpa_supplicant/wifi_display.c index c363b21b92b1..c94e4610893a 100644 --- a/contrib/wpa/wpa_supplicant/wifi_display.c +++ b/contrib/wpa/wpa_supplicant/wifi_display.c @@ -86,6 +86,7 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global) p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL); p2p_set_wfd_ie_go_neg(global->p2p, NULL); p2p_set_wfd_dev_info(global->p2p, NULL); + p2p_set_wfd_r2_dev_info(global->p2p, NULL); p2p_set_wfd_assoc_bssid(global->p2p, NULL); p2p_set_wfd_coupled_sink_info(global->p2p, NULL); return 0; @@ -93,6 +94,8 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global) p2p_set_wfd_dev_info(global->p2p, global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); + p2p_set_wfd_r2_dev_info( + global->p2p, global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]); p2p_set_wfd_assoc_bssid( global->p2p, global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]); @@ -133,6 +136,11 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global) if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) len += wpabuf_len(global->wfd_subelem[ WFD_SUBELEM_DEVICE_INFO]); + + if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]) + len += wpabuf_len(global->wfd_subelem[ + WFD_SUBELEM_R2_DEVICE_INFO]); + if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) len += wpabuf_len(global->wfd_subelem[ WFD_SUBELEM_ASSOCIATED_BSSID]); @@ -151,6 +159,11 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global) if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) wpabuf_put_buf(buf, global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); + + if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]) + wpabuf_put_buf(buf, + global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]); + if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) wpabuf_put_buf(buf, global->wfd_subelem[ WFD_SUBELEM_ASSOCIATED_BSSID]); diff --git a/contrib/wpa/wpa_supplicant/wmm_ac.c b/contrib/wpa/wpa_supplicant/wmm_ac.c index 5625d36638b5..38800cc77fb7 100644 --- a/contrib/wpa/wpa_supplicant/wmm_ac.c +++ b/contrib/wpa/wpa_supplicant/wmm_ac.c @@ -87,13 +87,10 @@ static int wmm_ac_add_ts(struct wpa_supplicant *wpa_s, const u8 *addr, } /* copy tspec */ - _tspec = os_malloc(sizeof(*_tspec)); + _tspec = os_memdup(tspec, sizeof(*_tspec)); if (!_tspec) return -1; - /* store the admitted TSPEC */ - os_memcpy(_tspec, tspec, sizeof(*_tspec)); - if (dir != WMM_AC_DIR_DOWNLINK) { ret = wpa_drv_add_ts(wpa_s, tsid, addr, up, admitted_time); wpa_printf(MSG_DEBUG, @@ -474,13 +471,8 @@ static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies, return -1; } - if (!ies) { - wpa_printf(MSG_ERROR, "WMM AC: Missing IEs"); - return -1; - } - - if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) { - wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration"); + if (!ies || !(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) { + /* WMM AC not in use for this connection */ return -1; } @@ -525,7 +517,7 @@ static void wmm_ac_deinit(struct wpa_supplicant *wpa_s) for (i = 0; i < WMM_AC_NUM; i++) wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL); - /* delete pending add_ts requset */ + /* delete pending add_ts request */ wmm_ac_del_req(wpa_s, 1); os_free(wpa_s->wmm_ac_assoc_info); diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.c b/contrib/wpa/wpa_supplicant/wnm_sta.c index 67a07ff7b1e7..22a21361ad8a 100644 --- a/contrib/wpa/wpa_supplicant/wnm_sta.c +++ b/contrib/wpa/wpa_supplicant/wnm_sta.c @@ -12,13 +12,16 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" +#include "common/ocv.h" #include "rsn_supp/wpa.h" +#include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "scan.h" #include "ctrl_iface.h" #include "bss.h" #include "wnm_sta.h" +#include "notify.h" #include "hs20_supplicant.h" #define MAX_TFS_IE_LEN 1024 @@ -57,8 +60,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, int res; size_t len; struct wnm_sleep_element *wnmsleep_ie; - u8 *wnmtfs_ie; - u8 wnmsleep_ie_len; + u8 *wnmtfs_ie, *oci_ie; + u8 wnmsleep_ie_len, oci_ie_len; u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : WNM_SLEEP_TFS_REQ_IE_NONE; @@ -84,12 +87,11 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, /* TFS IE(s) */ if (tfs_req) { wnmtfs_ie_len = wpabuf_len(tfs_req); - wnmtfs_ie = os_malloc(wnmtfs_ie_len); + wnmtfs_ie = os_memdup(wpabuf_head(tfs_req), wnmtfs_ie_len); if (wnmtfs_ie == NULL) { os_free(wnmsleep_ie); return -1; } - os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); } else { wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); if (wnmtfs_ie == NULL) { @@ -106,7 +108,41 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", (u8 *) wnmtfs_ie, wnmtfs_ie_len); - mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); + oci_ie = NULL; + oci_ie_len = 0; +#ifdef CONFIG_OCV + if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) { + struct wpa_channel_info ci; + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info for OCI element in WNM-Sleep Mode frame"); + os_free(wnmsleep_ie); + os_free(wnmtfs_ie); + return -1; + } + + oci_ie_len = OCV_OCI_EXTENDED_LEN; + oci_ie = os_zalloc(oci_ie_len); + if (!oci_ie) { + wpa_printf(MSG_WARNING, + "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame"); + os_free(wnmsleep_ie); + os_free(wnmtfs_ie); + return -1; + } + + if (ocv_insert_extended_oci(&ci, oci_ie) < 0) { + os_free(wnmsleep_ie); + os_free(wnmtfs_ie); + os_free(oci_ie); + return -1; + } + } +#endif /* CONFIG_OCV */ + + mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len + + oci_ie_len); if (mgmt == NULL) { wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " "WNM-Sleep Request action frame"); @@ -131,8 +167,16 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); } +#ifdef CONFIG_OCV + /* copy OCV OCI here */ + if (oci_ie_len > 0) { + os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + + wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len); + } +#endif /* CONFIG_OCV */ + len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + - wnmtfs_ie_len; + wnmtfs_ie_len + oci_ie_len; res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, @@ -145,6 +189,7 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, os_free(wnmsleep_ie); os_free(wnmtfs_ie); + os_free(oci_ie); os_free(mgmt); return res; @@ -256,6 +301,10 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, /* multiple TFS Resp IE (assuming consecutive) */ const u8 *tfsresp_ie_start = NULL; const u8 *tfsresp_ie_end = NULL; +#ifdef CONFIG_OCV + const u8 *oci_ie = NULL; + u8 oci_ie_len = 0; +#endif /* CONFIG_OCV */ size_t left; if (!wpa_s->wnmsleep_used) { @@ -289,6 +338,12 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, if (!tfsresp_ie_start) tfsresp_ie_start = pos; tfsresp_ie_end = pos; +#ifdef CONFIG_OCV + } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 && + pos[2] == WLAN_EID_EXT_OCV_OCI) { + oci_ie = pos + 3; + oci_ie_len = ie_len - 1; +#endif /* CONFIG_OCV */ } else wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); pos += ie_len + 2; @@ -299,6 +354,26 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, return; } +#ifdef CONFIG_OCV + if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT && + wpa_sm_ocv_enabled(wpa_s->wpa)) { + struct wpa_channel_info ci; + + if (wpa_drv_channel_info(wpa_s, &ci) != 0) { + wpa_msg(wpa_s, MSG_WARNING, + "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame"); + return; + } + + if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci, + channel_width_to_int(ci.chanwidth), + ci.seg1_idx) != 0) { + wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr); + return; + } + } +#endif /* CONFIG_OCV */ + wpa_s->wnmsleep_used = 0; if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || @@ -338,6 +413,9 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) wpa_s->wnm_num_neighbor_report = 0; os_free(wpa_s->wnm_neighbor_report_elements); wpa_s->wnm_neighbor_report_elements = NULL; + + wpabuf_free(wpa_s->coloc_intf_elems); + wpa_s->coloc_intf_elems = NULL; } @@ -501,10 +579,128 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, } +static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s) +{ + unsigned int i; + + for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) + wpa_s->wnm_neighbor_report_elements[i].acceptable = 0; +} + + +static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s) +{ + unsigned int i; + struct neighbor_report *nei; + + for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { + nei = &wpa_s->wnm_neighbor_report_elements[i]; + if (nei->acceptable) + return wpa_bss_get_bssid(wpa_s, nei->bssid); + } + + return NULL; +} + + +#ifdef CONFIG_MBO static struct wpa_bss * -compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) +get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, + enum mbo_transition_reject_reason *reason) { + struct wpa_bss *target = NULL; + struct wpa_bss_trans_info params; + struct wpa_bss_candidate_info *info = NULL; + struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements; + u8 *first_candidate_bssid = NULL, *pos; + unsigned int i; + + params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason; + params.n_candidates = 0; + params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN); + if (!params.bssid) + return NULL; + pos = params.bssid; + for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) { + if (nei->is_first) + first_candidate_bssid = nei->bssid; + if (!nei->acceptable) + continue; + os_memcpy(pos, nei->bssid, ETH_ALEN); + pos += ETH_ALEN; + params.n_candidates++; + } + + if (!params.n_candidates) + goto end; + + info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms); + if (!info) { + /* If failed to get candidate BSS transition status from driver, + * get the first acceptable candidate from wpa_supplicant. + */ + target = wpa_bss_get_bssid(wpa_s, params.bssid); + goto end; + } + + /* Get the first acceptable candidate from driver */ + for (i = 0; i < info->num; i++) { + if (info->candidates[i].is_accept) { + target = wpa_bss_get_bssid(wpa_s, + info->candidates[i].bssid); + goto end; + } + } + + /* If Disassociation Imminent is set and driver rejects all the + * candidate select first acceptable candidate which has + * rssi > disassoc_imminent_rssi_threshold + */ + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { + for (i = 0; i < info->num; i++) { + target = wpa_bss_get_bssid(wpa_s, + info->candidates[i].bssid); + if (target && + (target->level < + wpa_s->conf->disassoc_imminent_rssi_threshold)) + continue; + goto end; + } + } + + /* While sending BTM reject use reason code of the first candidate + * received in BTM request frame + */ + if (reason) { + for (i = 0; i < info->num; i++) { + if (first_candidate_bssid && + os_memcmp(first_candidate_bssid, + info->candidates[i].bssid, ETH_ALEN) == 0) + { + *reason = info->candidates[i].reject_reason; + break; + } + } + } + + target = NULL; + +end: + os_free(params.bssid); + if (info) { + os_free(info->candidates); + os_free(info); + } + return target; +} +#endif /* CONFIG_MBO */ + + +static struct wpa_bss * +compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, + enum mbo_transition_reject_reason *reason) +{ u8 i; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_bss *target; @@ -515,6 +711,8 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), bss->level); + wnm_clear_acceptable(wpa_s); + for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { struct neighbor_report *nei; @@ -564,7 +762,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) if (wpa_s->current_ssid && !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, - 1)) { + 1, 0)) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not match the current network profile", MAC2STR(nei->bssid), @@ -573,7 +771,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) continue; } - if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { + if (wpa_is_bss_tmp_disallowed(wpa_s, target)) { wpa_printf(MSG_DEBUG, "MBO: Candidate BSS " MACSTR " retry delay is not over yet", @@ -591,14 +789,26 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) continue; } + nei->acceptable = 1; + } + +#ifdef CONFIG_MBO + if (wpa_s->wnm_mbo_trans_reason_present) + target = get_mbo_transition_candidate(wpa_s, reason); + else + target = get_first_acceptable(wpa_s); +#else /* CONFIG_MBO */ + target = get_first_acceptable(wpa_s); +#endif /* CONFIG_MBO */ + + if (target) { wpa_printf(MSG_DEBUG, "WNM: Found an acceptable preferred transition candidate BSS " MACSTR " (RSSI %d)", - MAC2STR(nei->bssid), target->level); - return target; + MAC2STR(target->bssid), target->level); } - return NULL; + return target; } @@ -651,36 +861,40 @@ static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) } -static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info, - u8 op_class, u8 chan, u8 phy_type, u8 pref) +static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid, + u32 bss_info, u8 op_class, u8 chan, u8 phy_type, + u8 pref) { - u8 *pos = buf; + if (wpabuf_len(*buf) + 18 > + IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) { + wpa_printf(MSG_DEBUG, + "WNM: No room in frame for Neighbor Report element"); + return -1; + } - if (len < 18) { + if (wpabuf_resize(buf, 18) < 0) { wpa_printf(MSG_DEBUG, - "WNM: Not enough room for Neighbor Report element"); + "WNM: Failed to allocate memory for Neighbor Report element"); return -1; } - *pos++ = WLAN_EID_NEIGHBOR_REPORT; + wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT); /* length: 13 for basic neighbor report + 3 for preference subelement */ - *pos++ = 16; - os_memcpy(pos, bssid, ETH_ALEN); - pos += ETH_ALEN; - WPA_PUT_LE32(pos, bss_info); - pos += 4; - *pos++ = op_class; - *pos++ = chan; - *pos++ = phy_type; - *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE; - *pos++ = 1; - *pos++ = pref; - return pos - buf; + wpabuf_put_u8(*buf, 16); + wpabuf_put_data(*buf, bssid, ETH_ALEN); + wpabuf_put_le32(*buf, bss_info); + wpabuf_put_u8(*buf, op_class); + wpabuf_put_u8(*buf, chan); + wpabuf_put_u8(*buf, phy_type); + wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE); + wpabuf_put_u8(*buf, 1); + wpabuf_put_u8(*buf, pref); + return 0; } static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, u8 *buf, size_t len, + struct wpa_bss *bss, struct wpabuf **buf, u8 pref) { const u8 *ie; @@ -729,20 +943,19 @@ static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, info = wnm_get_bss_info(wpa_s, bss); - return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan, - phy_type, pref); + return wnm_add_nei_rep(buf, bss->bssid, info, op_class, chan, phy_type, + pref); } -static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) +static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf) { - u8 *pos = buf; unsigned int i, pref = 255; struct os_reltime now; struct wpa_ssid *ssid = wpa_s->current_ssid; if (!ssid) - return 0; + return; /* * TODO: Define when scan results are no longer valid for the candidate @@ -750,7 +963,7 @@ static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) */ os_get_reltime(&now); if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) - return 0; + return; wpa_printf(MSG_DEBUG, "WNM: Add candidate list to BSS Transition Management Response frame"); @@ -758,93 +971,103 @@ static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) struct wpa_bss *bss = wpa_s->last_scan_res[i]; int res; - if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) { - res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--); + if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) { + res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--); if (res == -2) continue; /* could not build entry for BSS */ if (res < 0) break; /* no more room for candidates */ if (pref == 1) break; - - pos += res; - len -= res; } } - wpa_hexdump(MSG_DEBUG, - "WNM: BSS Transition Management Response candidate list", - buf, pos - buf); - - return pos - buf; + wpa_hexdump_buf(MSG_DEBUG, + "WNM: BSS Transition Management Response candidate list", + *buf); } +#define BTM_RESP_MIN_SIZE 5 + ETH_ALEN + static void wnm_send_bss_transition_mgmt_resp( struct wpa_supplicant *wpa_s, u8 dialog_token, - enum bss_trans_mgmt_status_code status, u8 delay, - const u8 *target_bssid) + enum bss_trans_mgmt_status_code status, + enum mbo_transition_reject_reason reason, + u8 delay, const u8 *target_bssid) { - u8 buf[2000], *pos; - struct ieee80211_mgmt *mgmt; - size_t len; + struct wpabuf *buf; int res; - wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " - "to " MACSTR " dialog_token=%u status=%u delay=%d", - MAC2STR(wpa_s->bssid), dialog_token, status, delay); + wpa_printf(MSG_DEBUG, + "WNM: Send BSS Transition Management Response to " MACSTR + " dialog_token=%u status=%u reason=%u delay=%d", + MAC2STR(wpa_s->bssid), dialog_token, status, reason, delay); if (!wpa_s->current_bss) { wpa_printf(MSG_DEBUG, "WNM: Current BSS not known - drop response"); return; } - mgmt = (struct ieee80211_mgmt *) buf; - os_memset(&buf, 0, sizeof(buf)); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; - mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; - mgmt->u.action.u.bss_tm_resp.status_code = status; - mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; - pos = mgmt->u.action.u.bss_tm_resp.variable; + buf = wpabuf_alloc(BTM_RESP_MIN_SIZE); + if (!buf) { + wpa_printf(MSG_DEBUG, + "WNM: Failed to allocate memory for BTM response"); + return; + } + + wpa_s->bss_tm_status = status; + wpas_notify_bss_tm_status(wpa_s); + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP); + wpabuf_put_u8(buf, dialog_token); + wpabuf_put_u8(buf, status); + wpabuf_put_u8(buf, delay); if (target_bssid) { - os_memcpy(pos, target_bssid, ETH_ALEN); - pos += ETH_ALEN; + wpabuf_put_data(buf, target_bssid, ETH_ALEN); } else if (status == WNM_BSS_TM_ACCEPT) { /* * P802.11-REVmc clarifies that the Target BSSID field is always * present when status code is zero, so use a fake value here if * no BSSID is yet known. */ - os_memset(pos, 0, ETH_ALEN); - pos += ETH_ALEN; + wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN); } if (status == WNM_BSS_TM_ACCEPT) - pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); + wnm_add_cand_list(wpa_s, &buf); #ifdef CONFIG_MBO - if (status != WNM_BSS_TM_ACCEPT) { - pos += wpas_mbo_ie_bss_trans_reject( - wpa_s, pos, buf + sizeof(buf) - pos, - MBO_TRANSITION_REJECT_REASON_UNSPECIFIED); + if (status != WNM_BSS_TM_ACCEPT && + wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) { + u8 mbo[10]; + size_t ret; + + ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo), + reason); + if (ret) { + if (wpabuf_resize(&buf, ret) < 0) { + wpabuf_free(buf); + wpa_printf(MSG_DEBUG, + "WNM: Failed to allocate memory for MBO IE"); + return; + } + + wpabuf_put_data(buf, mbo, ret); + } } #endif /* CONFIG_MBO */ - len = pos - (u8 *) &mgmt->u.action.category; - res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); + wpabuf_head_u8(buf), wpabuf_len(buf), 0); if (res < 0) { wpa_printf(MSG_DEBUG, "WNM: Failed to send BSS Transition Management Response"); } + + wpabuf_free(buf); } @@ -863,10 +1086,10 @@ static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, wpa_s->wnm_reply = 0; wpa_printf(MSG_DEBUG, "WNM: Sending successful BSS Transition Management Response"); - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - WNM_BSS_TM_ACCEPT, - 0, bss->bssid); + wnm_send_bss_transition_mgmt_resp( + wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, + bss->bssid); } if (bss == wpa_s->current_bss) { @@ -888,6 +1111,8 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; + enum mbo_transition_reject_reason reason = + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; if (!wpa_s->wnm_neighbor_report_elements) return 0; @@ -909,7 +1134,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) } /* Compare the Neighbor Report and scan results */ - bss = compare_scan_neighbor_results(wpa_s, 0); + bss = compare_scan_neighbor_results(wpa_s, 0, &reason); if (!bss) { wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; @@ -930,7 +1155,7 @@ send_bss_resp_fail: wpa_s->wnm_reply = 0; wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, - status, 0, NULL); + status, reason, 0, NULL); } wnm_deallocate_memory(wpa_s); @@ -1118,7 +1343,7 @@ static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) return 0; } - bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE); + bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL); if (!bss) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Comparison of scan results against transition candidates did not find matches"); @@ -1144,6 +1369,11 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, if (end - pos < 5) return; +#ifdef CONFIG_MBO + wpa_s->wnm_mbo_trans_reason_present = 0; + wpa_s->wnm_mbo_transition_reason = 0; +#endif /* CONFIG_MBO */ + if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else @@ -1166,10 +1396,10 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_printf(MSG_INFO, "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", wpa_s->reject_btm_req_reason); - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - wpa_s->reject_btm_req_reason, - 0, NULL); + wnm_send_bss_transition_mgmt_resp( + wpa_s, wpa_s->wnm_dialog_token, + wpa_s->reject_btm_req_reason, + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); return; } #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ @@ -1248,6 +1478,15 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); wpa_s->wnm_num_neighbor_report++; +#ifdef CONFIG_MBO + if (wpa_s->wnm_mbo_trans_reason_present && + wpa_s->wnm_num_neighbor_report == 1) { + rep->is_first = 1; + wpa_printf(MSG_DEBUG, + "WNM: First transition candidate is " + MACSTR, MAC2STR(rep->bssid)); + } +#endif /* CONFIG_MBO */ } pos += len; @@ -1259,7 +1498,8 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, - 0, NULL); + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, + NULL); return; } @@ -1322,19 +1562,21 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); status = WNM_BSS_TM_REJECT_UNSPECIFIED; } - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - status, 0, NULL); + wnm_send_bss_transition_mgmt_resp( + wpa_s, wpa_s->wnm_dialog_token, status, + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); } } +#define BTM_QUERY_MIN_SIZE 4 + int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, - u8 query_reason, int cand_list) + u8 query_reason, + const char *btm_candidates, + int cand_list) { - u8 buf[2000], *pos; - struct ieee80211_mgmt *mgmt; - size_t len; + struct wpabuf *buf; int ret; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " @@ -1342,28 +1584,43 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, MAC2STR(wpa_s->bssid), query_reason, cand_list ? " candidate list" : ""); - mgmt = (struct ieee80211_mgmt *) buf; - os_memset(&buf, 0, sizeof(buf)); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; - mgmt->u.action.u.bss_tm_query.dialog_token = 1; - mgmt->u.action.u.bss_tm_query.query_reason = query_reason; - pos = mgmt->u.action.u.bss_tm_query.variable; + buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE); + if (!buf) + return -1; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY); + wpabuf_put_u8(buf, 1); + wpabuf_put_u8(buf, query_reason); if (cand_list) - pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); + wnm_add_cand_list(wpa_s, &buf); + + if (btm_candidates) { + const size_t max_len = 1000; + + ret = wpabuf_resize(&buf, max_len); + if (ret < 0) { + wpabuf_free(buf); + return ret; + } - len = pos - (u8 *) &mgmt->u.action.category; + ret = ieee802_11_parse_candidate_list(btm_candidates, + wpabuf_put(buf, 0), + max_len); + if (ret < 0) { + wpabuf_free(buf); + return ret; + } + + wpabuf_put(buf, ret); + } ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); + wpabuf_head_u8(buf), wpabuf_len(buf), 0); + wpabuf_free(buf); return ret; } @@ -1468,6 +1725,32 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, pos = next; continue; } + + if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && + WPA_GET_BE24(pos) == OUI_WFA && + pos[3] == HS20_WNM_T_C_ACCEPTANCE) { + const u8 *ie_end; + u8 url_len; + char *url; + + ie_end = pos + ie_len; + pos += 4; + url_len = *pos++; + wpa_printf(MSG_DEBUG, + "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)", + url_len); + if (url_len > ie_end - pos) + break; + url = os_malloc(url_len + 1); + if (!url) + break; + os_memcpy(url, pos, url_len); + url[url_len] = '\0'; + hs20_rx_t_c_acceptance(wpa_s, url); + os_free(url); + pos = next; + continue; + } #endif /* CONFIG_HS20 */ pos = next; @@ -1515,6 +1798,46 @@ static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, } +static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s, + const u8 *sa, const u8 *frm, + int len) +{ + u8 dialog_token, req_info, auto_report, timeout; + + if (!wpa_s->conf->coloc_intf_reporting) + return; + + /* Dialog Token [1] | Request Info [1] */ + + if (len < 2) + return; + dialog_token = frm[0]; + req_info = frm[1]; + auto_report = req_info & 0x03; + timeout = req_info >> 2; + + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")", + dialog_token, auto_report, timeout, MAC2STR(sa)); + + if (dialog_token == 0) + return; /* only nonzero values are used for request */ + + if (wpa_s->wpa_state != WPA_COMPLETED || + os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Collocated Interference Request frame not from current AP - ignore it"); + return; + } + + wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u", + dialog_token, auto_report, timeout); + wpa_s->coloc_intf_dialog_token = dialog_token; + wpa_s->coloc_intf_auto_report = auto_report; + wpa_s->coloc_intf_timeout = timeout; +} + + void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -1548,8 +1871,75 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, case WNM_NOTIFICATION_REQ: ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); break; + case WNM_COLLOCATED_INTERFERENCE_REQ: + ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos, + end - pos); + break; default: wpa_printf(MSG_ERROR, "WNM: Unknown request"); break; } } + + +int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, + const struct wpabuf *elems) +{ + struct wpabuf *buf; + int ret; + + if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems) + return -1; + + wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to " + MACSTR " (dialog token %u)", + MAC2STR(wpa_s->bssid), dialog_token); + + buf = wpabuf_alloc(3 + wpabuf_len(elems)); + if (!buf) + return -1; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT); + wpabuf_put_u8(buf, dialog_token); + wpabuf_put_buf(buf, elems); + + ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head_u8(buf), wpabuf_len(buf), 0); + wpabuf_free(buf); + return ret; +} + + +void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, + struct wpabuf *elems) +{ + wpabuf_free(wpa_s->coloc_intf_elems); + if (elems && wpabuf_len(elems) == 0) { + wpabuf_free(elems); + elems = NULL; + } + wpa_s->coloc_intf_elems = elems; + + if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems && + wpa_s->coloc_intf_dialog_token && + (wpa_s->coloc_intf_auto_report == 1 || + wpa_s->coloc_intf_auto_report == 3)) { + /* TODO: Check that there has not been less than + * wpa_s->coloc_intf_timeout * 200 TU from the last report. + */ + wnm_send_coloc_intf_report(wpa_s, + wpa_s->coloc_intf_dialog_token, + wpa_s->coloc_intf_elems); + } +} + + +void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_WNM + wpa_s->coloc_intf_dialog_token = 0; + wpa_s->coloc_intf_auto_report = 0; +#endif /* CONFIG_WNM */ +} diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.h b/contrib/wpa/wpa_supplicant/wnm_sta.h index 81d815359634..29625f8ca943 100644 --- a/contrib/wpa/wpa_supplicant/wnm_sta.h +++ b/contrib/wpa/wpa_supplicant/wnm_sta.h @@ -43,6 +43,10 @@ struct neighbor_report { unsigned int rm_capab_present:1; unsigned int bearing_present:1; unsigned int bss_term_present:1; + unsigned int acceptable:1; +#ifdef CONFIG_MBO + unsigned int is_first:1; +#endif /* CONFIG_MBO */ struct measurement_pilot *meas_pilot; struct multiple_bssid *mul_bssid; int freq; @@ -56,13 +60,21 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len); int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, - u8 query_reason, int cand_list); + u8 query_reason, + const char *btm_candidates, + int cand_list); + void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); +int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, + const struct wpabuf *elems); +void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, + struct wpabuf *elems); #ifdef CONFIG_WNM int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail); +void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s); #else /* CONFIG_WNM */ @@ -72,6 +84,10 @@ static inline int wnm_scan_process(struct wpa_supplicant *wpa_s, return 0; } +static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) +{ +} + #endif /* CONFIG_WNM */ #endif /* WNM_STA_H */ diff --git a/contrib/wpa/wpa_supplicant/wpa_cli.c b/contrib/wpa/wpa_supplicant/wpa_cli.c index a848b7737db5..695fcbe04995 100644 --- a/contrib/wpa/wpa_supplicant/wpa_cli.c +++ b/contrib/wpa/wpa_supplicant/wpa_cli.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - command line interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -29,7 +29,7 @@ static const char *const wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors"; #define VENDOR_ELEM_FRAME_ID \ " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \ @@ -49,6 +49,7 @@ static int wpa_cli_last_id = 0; static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; static const char *client_socket_dir = NULL; static char *ctrl_ifname = NULL; +static const char *global = NULL; static const char *pid_file = NULL; static const char *action_file = NULL; static int ping_interval = 5; @@ -60,6 +61,10 @@ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(creds); /* struct cli_txt_entry */ +#ifdef CONFIG_AP +static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */ +#endif /* CONFIG_AP */ static void print_help(const char *cmd); @@ -67,7 +72,10 @@ static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); static void wpa_cli_close_connection(void); static char * wpa_cli_get_default_ifname(void); static char ** wpa_list_cmd_list(void); +static void update_creds(struct wpa_ctrl *ctrl); static void update_networks(struct wpa_ctrl *ctrl); +static void update_stations(struct wpa_ctrl *ctrl); +static void update_ifnames(struct wpa_ctrl *ctrl); static void usage(void) @@ -214,7 +222,7 @@ static void wpa_cli_msg_cb(char *msg, size_t len) } -static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) +static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print) { char buf[4096]; size_t len; @@ -250,7 +258,7 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) } -static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) +static int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd) { return _wpa_ctrl_command(ctrl, cmd, 1); } @@ -331,6 +339,39 @@ static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, } +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + +static int wpa_cli_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PMKSA_GET", 1, argc, argv); +} + + +static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv); +} + + +#ifdef CONFIG_MESH + +static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv); +} + + +static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv); +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) { print_help(argc > 0 ? argv[0] : NULL); @@ -437,11 +478,13 @@ static char ** wpa_cli_complete_set(const char *str, int pos) #endif /* CONFIG_P2P */ "country", "bss_max_count", "bss_expiration_age", "bss_expiration_scan_count", "filter_ssids", "filter_rssi", - "max_num_sta", "disassoc_low_ack", + "max_num_sta", "disassoc_low_ack", "ap_isolate", #ifdef CONFIG_HS20 "hs20", #endif /* CONFIG_HS20 */ "interworking", "hessid", "access_network_type", "pbc_in_m1", + "go_interworking", "go_access_network_type", "go_internet", + "go_venue_group", "go_venue_type", "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend", "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", @@ -455,6 +498,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) #ifdef CONFIG_TESTING_OPTIONS "ignore_auth_resp", #endif /* CONFIG_TESTING_OPTIONS */ + "relative_rssi", "relative_band_adjust", }; int i, num_fields = ARRAY_SIZE(fields); @@ -531,15 +575,18 @@ static char ** wpa_cli_complete_get(const char *str, int pos) #endif /* CONFIG_P2P */ "bss_max_count", "bss_expiration_age", "bss_expiration_scan_count", "filter_ssids", "filter_rssi", - "max_num_sta", "disassoc_low_ack", + "max_num_sta", "disassoc_low_ack", "ap_isolate", #ifdef CONFIG_HS20 "hs20", #endif /* CONFIG_HS20 */ "interworking", "access_network_type", "pbc_in_m1", "autoscan", + "go_interworking", "go_access_network_type", "go_internet", + "go_venue_group", "go_venue_type", "wps_nfc_dev_pw_id", "ext_password_backend", "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", "dtim_period", "beacon_int", "ignore_old_scan_res", "scan_cur_freq", "sched_scan_interval", + "sched_scan_start_delay", "tdls_external_control", "osu_dir", "wowlan_triggers", "p2p_search_delay", "mac_addr", "rand_addr_lifetime", "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", @@ -639,13 +686,6 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) } -static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv); -} - - static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv); @@ -1165,6 +1205,39 @@ static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_psk_passphrase(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid PSK_PASSPHRASE command: needs two arguments (network id and PSK/passphrase)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PSK_PASSPHRASE-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + printf("Too long PSK_PASSPHRASE command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + printf("Too long PSK_PASSPHRASE command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1332,14 +1405,17 @@ static const char *network_fields[] = { "ssid", "scan_ssid", "bssid", "bssid_blacklist", "bssid_whitelist", "psk", "proto", "key_mgmt", "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq", - "freq_list", "max_oper_chwidth", + "freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1", + "vht_center_freq2", "ht", #ifdef IEEE8021X_EAPOL "eap", "identity", "anonymous_identity", "password", "ca_cert", "ca_path", "client_cert", "private_key", "private_key_passwd", "dh_file", "subject_match", "altsubject_match", + "check_cert_subject", "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2", "client_cert2", "private_key2", "private_key2_passwd", "dh_file2", "subject_match2", "altsubject_match2", + "check_cert_subject2", "domain_suffix_match2", "domain_match2", "phase1", "phase2", "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id", "pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id", @@ -1352,7 +1428,7 @@ static const char *network_fields[] = { "eap_workaround", "pac_file", "fragment_size", "ocsp", #endif /* IEEE8021X_EAPOL */ #ifdef CONFIG_MESH - "mode", "no_auto_peer", + "mode", "no_auto_peer", "mesh_rssi_threshold", #else /* CONFIG_MESH */ "mode", #endif /* CONFIG_MESH */ @@ -1360,7 +1436,7 @@ static const char *network_fields[] = { #ifdef CONFIG_IEEE80211W "ieee80211w", #endif /* CONFIG_IEEE80211W */ - "peerkey", "mixed_cell", "frequency", "fixed_freq", + "mixed_cell", "frequency", "fixed_freq", #ifdef CONFIG_MESH "mesh_basic_rates", "dot11MeshMaxRetries", "dot11MeshRetryTimeout", "dot11MeshConfirmTimeout", @@ -1373,7 +1449,7 @@ static const char *network_fields[] = { #ifdef CONFIG_HT_OVERRIDES "disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc", "ht40_intolerant", "disable_max_amsdu", "ampdu_factor", - "ampdu_density", "ht_mcs", + "ampdu_density", "ht_mcs", "rx_stbc", "tx_stbc", #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES "disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1", @@ -1386,6 +1462,11 @@ static const char *network_fields[] = { "ap_max_inactivity", "dtim_period", "beacon_int", #ifdef CONFIG_MACSEC "macsec_policy", + "macsec_integ_only", + "macsec_replay_protect", + "macsec_replay_window", + "macsec_port", + "mka_priority", #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 "update_identifier", @@ -1479,14 +1560,56 @@ static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_ctrl_command(ctrl, "ADD_CRED"); + int res = wpa_ctrl_command(ctrl, "ADD_CRED"); + if (interactive) + update_creds(ctrl); + return res; } static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); + int res = wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); + if (interactive) + update_creds(ctrl); + return res; +} + + +static const char * const cred_fields[] = { + "temporary", "priority", "sp_priority", "pcsc", "eap", + "update_identifier", "min_dl_bandwidth_home", "min_ul_bandwidth_home", + "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load", + "req_conn_capab", "ocsp", "sim_num", "realm", "username", "password", + "ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi", + "milenage", "domain_suffix_match", "domain", "phase1", "phase2", + "roaming_consortium", "required_roaming_consortium", "excluded_ssid", + "roaming_partner", "provisioning_sp" +}; + + +static char ** wpa_cli_complete_cred(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + int i, num_fields = ARRAY_SIZE(cred_fields); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&creds); + break; + case 2: + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(cred_fields[i]); + if (res[i] == NULL) + break; + } + } + return res; } @@ -1736,8 +1859,23 @@ static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) } -static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, - char *addr, size_t addr_len) +static char ** wpa_cli_complete_sta(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + +static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd, + char *addr, size_t addr_len, int print) { char buf[4096], *pos; size_t len; @@ -1765,9 +1903,11 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, } buf[len] = '\0'; - if (os_memcmp(buf, "FAIL", 4) == 0) + if (os_memcmp(buf, "FAIL", 4) == 0 || + os_memcmp(buf, "UNKNOWN COMMAND", 15) == 0) return -1; - printf("%s", buf); + if (print) + printf("%s", buf); pos = buf; while (*pos != '\0' && *pos != '\n') @@ -1782,16 +1922,33 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char addr[32], cmd[64]; - if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) + if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1)) return 0; do { os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); - } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); + } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0); return -1; } +static int wpa_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char addr[32], cmd[64]; + + if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0)) + return 0; + do { + if (os_strcmp(addr, "") != 0) + printf("%s\n", addr); + os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); + } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0); + + return 0; +} + + static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1799,12 +1956,43 @@ static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, } +static char ** wpa_cli_complete_deauthenticate(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv); } + +static char ** wpa_cli_complete_disassociate(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2176,7 +2364,7 @@ static char ** wpa_cli_complete_p2p_peer(const char *str, int pos) } -static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd, +static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, const char *cmd, char *addr, size_t addr_len, int discovered) { @@ -2338,6 +2526,8 @@ static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc, return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv); } +#endif /* CONFIG_P2P */ + static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) @@ -2359,7 +2549,6 @@ static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc, return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv); } -#endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY @@ -2726,6 +2915,108 @@ static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc, } +#ifdef CONFIG_DPP + +static int wpa_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN"); +} + + +static int wpa_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv); +} + + +static int wpa_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); +} + +#endif /* CONFIG_DPP */ + + enum wpa_cli_cmd_flags { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 @@ -2798,6 +3089,22 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL, cli_cmd_flag_none, "= flush PMKSA cache entries" }, +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + { "pmksa_get", wpa_cli_cmd_pmksa_get, NULL, + cli_cmd_flag_none, + "<network_id> = fetch all stored PMKSA cache entries" }, + { "pmksa_add", wpa_cli_cmd_pmksa_add, NULL, + cli_cmd_flag_sensitive, + "<network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> <expiration in seconds> <akmp> <opportunistic> = store PMKSA cache entry from external storage" }, +#ifdef CONFIG_MESH + { "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL, + cli_cmd_flag_none, + "<peer MAC address | any> = fetch all stored mesh PMKSA cache entries" }, + { "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL, + cli_cmd_flag_sensitive, + "<BSSID> <PMKID> <PMK> <expiration in seconds> = store mesh PMKSA cache entry from external storage" }, +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ { "reassociate", wpa_cli_cmd_reassociate, NULL, cli_cmd_flag_none, "= force reassociation" }, @@ -2807,30 +3114,33 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss, cli_cmd_flag_none, "<BSSID> = force preauthentication" }, - { "identity", wpa_cli_cmd_identity, NULL, + { "identity", wpa_cli_cmd_identity, wpa_cli_complete_network_id, cli_cmd_flag_none, "<network id> <identity> = configure identity for an SSID" }, - { "password", wpa_cli_cmd_password, NULL, + { "password", wpa_cli_cmd_password, wpa_cli_complete_network_id, cli_cmd_flag_sensitive, "<network id> <password> = configure password for an SSID" }, - { "new_password", wpa_cli_cmd_new_password, NULL, - cli_cmd_flag_sensitive, + { "new_password", wpa_cli_cmd_new_password, + wpa_cli_complete_network_id, cli_cmd_flag_sensitive, "<network id> <password> = change password for an SSID" }, - { "pin", wpa_cli_cmd_pin, NULL, + { "pin", wpa_cli_cmd_pin, wpa_cli_complete_network_id, cli_cmd_flag_sensitive, "<network id> <pin> = configure pin for an SSID" }, - { "otp", wpa_cli_cmd_otp, NULL, + { "otp", wpa_cli_cmd_otp, wpa_cli_complete_network_id, cli_cmd_flag_sensitive, "<network id> <password> = configure one-time-password for an SSID" }, - { "passphrase", wpa_cli_cmd_passphrase, NULL, + { "psk_passphrase", wpa_cli_cmd_psk_passphrase, + wpa_cli_complete_network_id, cli_cmd_flag_sensitive, + "<network id> <PSK/passphrase> = configure PSK/passphrase for an SSID" }, + { "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id, cli_cmd_flag_sensitive, "<network id> <passphrase> = configure private key passphrase\n" " for an SSID" }, - { "sim", wpa_cli_cmd_sim, NULL, + { "sim", wpa_cli_cmd_sim, wpa_cli_complete_network_id, cli_cmd_flag_sensitive, "<network id> <pin> = report SIM operation result" }, - { "bssid", wpa_cli_cmd_bssid, NULL, + { "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id, cli_cmd_flag_none, "<network id> <BSSID> = set preferred BSSID for an SSID" }, { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss, @@ -2884,10 +3194,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "remove_cred", wpa_cli_cmd_remove_cred, NULL, cli_cmd_flag_none, "<cred id> = remove a credential" }, - { "set_cred", wpa_cli_cmd_set_cred, NULL, + { "set_cred", wpa_cli_cmd_set_cred, wpa_cli_complete_cred, cli_cmd_flag_sensitive, "<cred id> <variable> <value> = set credential variables" }, - { "get_cred", wpa_cli_cmd_get_cred, NULL, + { "get_cred", wpa_cli_cmd_get_cred, wpa_cli_complete_cred, cli_cmd_flag_none, "<cred id> <variable> = get credential variables" }, { "save_config", wpa_cli_cmd_save_config, NULL, @@ -2951,9 +3261,6 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "bss_flush", wpa_cli_cmd_bss_flush, NULL, cli_cmd_flag_none, "<value> = set BSS flush age (0 by default)" }, - { "stkstart", wpa_cli_cmd_stkstart, NULL, - cli_cmd_flag_none, - "<addr> = request STK negotiation with <addr>" }, { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss, cli_cmd_flag_none, "<addr> = request over-the-DS FT with <addr>" }, @@ -3029,17 +3336,20 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { cli_cmd_flag_none, "<addr> = request RSN authentication with <addr> in IBSS" }, #ifdef CONFIG_AP - { "sta", wpa_cli_cmd_sta, NULL, + { "sta", wpa_cli_cmd_sta, wpa_cli_complete_sta, cli_cmd_flag_none, "<addr> = get information about an associated station (AP)" }, { "all_sta", wpa_cli_cmd_all_sta, NULL, cli_cmd_flag_none, "= get information about all associated stations (AP)" }, - { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL, + { "list_sta", wpa_cli_cmd_list_sta, NULL, cli_cmd_flag_none, + "= list all stations (AP)" }, + { "deauthenticate", wpa_cli_cmd_deauthenticate, + wpa_cli_complete_deauthenticate, cli_cmd_flag_none, "<addr> = deauthenticate a station" }, - { "disassociate", wpa_cli_cmd_disassociate, NULL, - cli_cmd_flag_none, + { "disassociate", wpa_cli_cmd_disassociate, + wpa_cli_complete_disassociate, cli_cmd_flag_none, "<addr> = disassociate a station" }, { "chan_switch", wpa_cli_cmd_chanswitch, NULL, cli_cmd_flag_none, @@ -3168,6 +3478,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "<address|iface=address> = remove a peer from all groups" }, +#endif /* CONFIG_P2P */ { "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL, cli_cmd_flag_none, "<frame id> <hexdump of elem(s)> = add vendor specific IEs to frame(s)\n" @@ -3180,7 +3491,6 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { cli_cmd_flag_none, "<frame id> <hexdump of elem(s)> = remove vendor specific IE(s) in frame(s)\n" VENDOR_ELEM_FRAME_ID }, -#endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL, cli_cmd_flag_none, @@ -3285,7 +3595,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none, "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" }, { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none, - "<query reason> [list] = Send BSS Transition Management Query" }, + "<query reason> [list]" + " [neighbor=<BSSID>,<BSSID information>,<operating class>,<channel number>,<PHY type>[,<hexdump of optional subelements>]" + " = Send BSS Transition Management Query" }, #endif /* CONFIG_WNM */ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, "<params..> = Sent unprocessed command" }, @@ -3320,6 +3632,47 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL, cli_cmd_flag_none, "= stop P2P listen offload" }, +#ifdef CONFIG_DPP + { "dpp_qr_code", wpa_cli_cmd_dpp_qr_code, NULL, cli_cmd_flag_none, + "report a scanned DPP URI from a QR Code" }, + { "dpp_bootstrap_gen", wpa_cli_cmd_dpp_bootstrap_gen, NULL, + cli_cmd_flag_sensitive, + "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" }, + { "dpp_bootstrap_remove", wpa_cli_cmd_dpp_bootstrap_remove, NULL, + cli_cmd_flag_none, + "*|<id> = remove DPP bootstrap information" }, + { "dpp_bootstrap_get_uri", wpa_cli_cmd_dpp_bootstrap_get_uri, NULL, + cli_cmd_flag_none, + "<id> = get DPP bootstrap URI" }, + { "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL, + cli_cmd_flag_none, + "<id> = show DPP bootstrap information" }, + { "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none, + "peer=<id> [own=<id>] = initiate DPP bootstrapping" }, + { "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none, + "<freq in MHz> = start DPP listen" }, + { "dpp_stop_listen", wpa_cli_cmd_dpp_stop_listen, NULL, + cli_cmd_flag_none, + "= stop DPP listen" }, + { "dpp_configurator_add", wpa_cli_cmd_dpp_configurator_add, NULL, + cli_cmd_flag_sensitive, + "[curve=..] [key=..] = add DPP configurator" }, + { "dpp_configurator_remove", wpa_cli_cmd_dpp_configurator_remove, NULL, + cli_cmd_flag_none, + "*|<id> = remove DPP configurator" }, + { "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key, + NULL, cli_cmd_flag_none, + "<id> = Get DPP configurator's private key" }, + { "dpp_configurator_sign", wpa_cli_cmd_dpp_configurator_sign, NULL, + cli_cmd_flag_none, + "conf=<role> configurator=<id> = generate self DPP configuration" }, + { "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL, + cli_cmd_flag_sensitive, + "add PKEX code" }, + { "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL, + cli_cmd_flag_none, + "*|<id> = remove DPP pkex information" }, +#endif /* CONFIG_DPP */ { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; @@ -3638,6 +3991,10 @@ static void wpa_cli_action_process(const char *msg) wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, WPS_EVENT_SUCCESS)) { 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_TIMEOUT)) { + wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, WPS_EVENT_FAIL)) { wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, AP_STA_CONNECTED)) { @@ -3650,6 +4007,8 @@ static void wpa_cli_action_process(const char *msg) wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) { wpa_cli_exec(action_file, ifname, pos); + } else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) { + wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, WPA_EVENT_TERMINATING)) { printf("wpa_supplicant is terminating - stop monitoring\n"); wpa_cli_quit = 1; @@ -3665,16 +4024,53 @@ static void wpa_cli_action_cb(char *msg, size_t len) #endif /* CONFIG_ANSI_C_EXTRA */ +static int wpa_cli_open_global_ctrl(void) +{ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + ctrl_conn = wpa_ctrl_open(NULL); +#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + ctrl_conn = wpa_ctrl_open(global); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + if (!ctrl_conn) { + fprintf(stderr, + "Failed to connect to wpa_supplicant global interface: %s error: %s\n", + global, strerror(errno)); + return -1; + } + + if (interactive) { + update_ifnames(ctrl_conn); + mon_conn = wpa_ctrl_open(global); + if (mon_conn) { + if (wpa_ctrl_attach(mon_conn) == 0) { + wpa_cli_attached = 1; + eloop_register_read_sock( + wpa_ctrl_get_fd(mon_conn), + wpa_cli_mon_receive, + NULL, NULL); + } else { + printf("Failed to open monitor connection through global control interface\n"); + } + } + update_stations(ctrl_conn); + } + + return 0; +} + + static void wpa_cli_reconnect(void) { wpa_cli_close_connection(); - if (wpa_cli_open_connection(ctrl_ifname, 1) < 0) + if ((global && wpa_cli_open_global_ctrl() < 0) || + (!global && wpa_cli_open_connection(ctrl_ifname, 1) < 0)) return; if (interactive) { edit_clear_line(); printf("\rConnection to wpa_supplicant re-established\n"); edit_redraw(); + update_stations(ctrl_conn); } } @@ -3897,7 +4293,7 @@ static void update_bssid_list(struct wpa_ctrl *ctrl) char buf[4096]; size_t len = sizeof(buf); int ret; - char *cmd = "BSS RANGE=ALL MASK=0x2"; + const char *cmd = "BSS RANGE=ALL MASK=0x2"; char *pos, *end; if (ctrl == NULL) @@ -3928,7 +4324,7 @@ static void update_ifnames(struct wpa_ctrl *ctrl) char buf[4096]; size_t len = sizeof(buf); int ret; - char *cmd = "INTERFACES"; + const char *cmd = "INTERFACES"; char *pos, *end; char txt[200]; @@ -3955,12 +4351,44 @@ static void update_ifnames(struct wpa_ctrl *ctrl) } +static void update_creds(struct wpa_ctrl *ctrl) +{ + char buf[4096]; + size_t len = sizeof(buf); + int ret; + const char *cmd = "LIST_CREDS"; + char *pos, *end; + int header = 1; + + cli_txt_list_flush(&creds); + + if (ctrl == NULL) + return; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); + if (ret < 0) + return; + buf[len] = '\0'; + + pos = buf; + while (pos) { + end = os_strchr(pos, '\n'); + if (end == NULL) + break; + *end = '\0'; + if (!header) + cli_txt_list_add_word(&creds, pos, '\t'); + header = 0; + pos = end + 1; + } +} + + static void update_networks(struct wpa_ctrl *ctrl) { char buf[4096]; size_t len = sizeof(buf); int ret; - char *cmd = "LIST_NETWORKS"; + const char *cmd = "LIST_NETWORKS"; char *pos, *end; int header = 1; @@ -3987,6 +4415,27 @@ static void update_networks(struct wpa_ctrl *ctrl) } +static void update_stations(struct wpa_ctrl *ctrl) +{ +#ifdef CONFIG_AP + char addr[32], cmd[64]; + + if (!ctrl || !interactive) + return; + + cli_txt_list_flush(&stations); + + if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0)) + return; + do { + if (os_strcmp(addr, "") != 0) + cli_txt_list_add(&stations, addr); + os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); + } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0); +#endif /* CONFIG_AP */ +} + + static void try_connection(void *eloop_ctx, void *timeout_ctx) { if (ctrl_conn) @@ -4007,7 +4456,9 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx) } update_bssid_list(ctrl_conn); + update_creds(ctrl_conn); update_networks(ctrl_conn); + update_stations(ctrl_conn); if (warning_displayed) printf("Connection established.\n"); @@ -4029,6 +4480,7 @@ static void wpa_cli_interactive(void) cli_txt_list_flush(&p2p_groups); cli_txt_list_flush(&bsses); cli_txt_list_flush(&ifnames); + cli_txt_list_flush(&creds); cli_txt_list_flush(&networks); if (edit_started) edit_deinit(hfile, wpa_cli_edit_filter_history_cb); @@ -4170,7 +4622,6 @@ int main(int argc, char *argv[]) int c; int daemonize = 0; int ret = 0; - const char *global = NULL; if (os_program_init()) return -1; @@ -4225,37 +4676,8 @@ int main(int argc, char *argv[]) if (eloop_init()) return -1; - if (global) { -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - ctrl_conn = wpa_ctrl_open(NULL); -#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ - ctrl_conn = wpa_ctrl_open(global); -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ - if (ctrl_conn == NULL) { - fprintf(stderr, "Failed to connect to wpa_supplicant " - "global interface: %s error: %s\n", - global, strerror(errno)); - return -1; - } - - if (interactive) { - update_ifnames(ctrl_conn); - mon_conn = wpa_ctrl_open(global); - if (mon_conn) { - if (wpa_ctrl_attach(mon_conn) == 0) { - wpa_cli_attached = 1; - eloop_register_read_sock( - wpa_ctrl_get_fd(mon_conn), - wpa_cli_mon_receive, - NULL, NULL); - } else { - printf("Failed to open monitor " - "connection through global " - "control interface\n"); - } - } - } - } + if (global && wpa_cli_open_global_ctrl() < 0) + return -1; eloop_register_signal_terminate(wpa_cli_terminate, NULL); diff --git a/contrib/wpa/wpa_supplicant/wpa_passphrase.c b/contrib/wpa/wpa_supplicant/wpa_passphrase.c index 9b568f0f7c67..adca1cce13ee 100644 --- a/contrib/wpa/wpa_supplicant/wpa_passphrase.c +++ b/contrib/wpa/wpa_supplicant/wpa_passphrase.c @@ -17,6 +17,7 @@ int main(int argc, char *argv[]) unsigned char psk[32]; int i; char *ssid, *passphrase, buf[64], *pos; + size_t len; if (argc < 2) { printf("usage: wpa_passphrase <ssid> [passphrase]\n" @@ -47,10 +48,15 @@ int main(int argc, char *argv[]) passphrase = buf; } - if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) { + len = os_strlen(passphrase); + if (len < 8 || len > 63) { printf("Passphrase must be 8..63 characters\n"); return 1; } + if (has_ctrl_char((u8 *) passphrase, len)) { + printf("Invalid passphrase character\n"); + return 1; + } pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32); diff --git a/contrib/wpa/wpa_supplicant/wpa_priv.c b/contrib/wpa/wpa_supplicant/wpa_priv.c index 511df4f18148..b3ad45eca516 100644 --- a/contrib/wpa/wpa_supplicant/wpa_priv.c +++ b/contrib/wpa/wpa_supplicant/wpa_priv.c @@ -21,6 +21,7 @@ #include "common/privsep_commands.h" #include "common/ieee802_11_defs.h" +#define WPA_PRIV_MAX_L2 3 struct wpa_priv_interface { struct wpa_priv_interface *next; @@ -35,11 +36,16 @@ struct wpa_priv_interface { void *drv_priv; void *drv_global_priv; struct sockaddr_un drv_addr; + socklen_t drv_addr_len; int wpas_registered; - /* TODO: add support for multiple l2 connections */ - struct l2_packet_data *l2; - struct sockaddr_un l2_addr; + struct l2_packet_data *l2[WPA_PRIV_MAX_L2]; + struct sockaddr_un l2_addr[WPA_PRIV_MAX_L2]; + socklen_t l2_addr_len[WPA_PRIV_MAX_L2]; + struct wpa_priv_l2 { + struct wpa_priv_interface *parent; + int idx; + } l2_ctx[WPA_PRIV_MAX_L2]; }; struct wpa_priv_global { @@ -48,8 +54,10 @@ struct wpa_priv_global { static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, socklen_t fromlen) { + int i; + if (iface->drv_priv) { wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance"); if (iface->driver->deinit) @@ -62,11 +70,13 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, iface->wpas_registered = 0; } - if (iface->l2) { - wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " - "instance"); - l2_packet_deinit(iface->l2); - iface->l2 = NULL; + for (i = 0; i < WPA_PRIV_MAX_L2; i++) { + if (iface->l2[i]) { + wpa_printf(MSG_DEBUG, + "Cleaning up forgotten l2_packet instance"); + l2_packet_deinit(iface->l2[i]); + iface->l2[i] = NULL; + } } if (iface->driver->init2) { @@ -96,7 +106,8 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface " "'%s'", iface->driver_name, iface->ifname); - os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr)); + os_memcpy(&iface->drv_addr, from, fromlen); + iface->drv_addr_len = fromlen; iface->wpas_registered = 1; if (iface->driver->set_param && @@ -123,18 +134,43 @@ static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface, static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface, - char *buf, size_t len) + void *buf, size_t len) { struct wpa_driver_scan_params params; + struct privsep_cmd_scan *scan; + unsigned int i; + int freqs[PRIVSEP_MAX_SCAN_FREQS + 1]; if (iface->drv_priv == NULL) return; + if (len < sizeof(*scan)) { + wpa_printf(MSG_DEBUG, "Invalid scan request"); + return; + } + + scan = buf; + os_memset(¶ms, 0, sizeof(params)); - if (len) { - params.ssids[0].ssid = (u8 *) buf; - params.ssids[0].ssid_len = len; - params.num_ssids = 1; + if (scan->num_ssids > WPAS_MAX_SCAN_SSIDS) { + wpa_printf(MSG_DEBUG, "Invalid scan request (num_ssids)"); + return; + } + params.num_ssids = scan->num_ssids; + for (i = 0; i < scan->num_ssids; i++) { + params.ssids[i].ssid = scan->ssids[i]; + params.ssids[i].ssid_len = scan->ssid_lens[i]; + } + + if (scan->num_freqs > PRIVSEP_MAX_SCAN_FREQS) { + wpa_printf(MSG_DEBUG, "Invalid scan request (num_freqs)"); + return; + } + if (scan->num_freqs) { + for (i = 0; i < scan->num_freqs; i++) + freqs[i] = scan->freqs[i]; + freqs[i] = 0; + params.freqs = freqs; } if (iface->driver->scan2) @@ -143,7 +179,8 @@ static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface, static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, + socklen_t fromlen) { struct wpa_scan_results *res; u8 *buf = NULL, *pos, *end; @@ -165,7 +202,7 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, for (i = 0; i < res->num; i++) { struct wpa_scan_res *r = res->res[i]; - val = sizeof(*r) + r->ie_len; + val = sizeof(*r) + r->ie_len + r->beacon_ie_len; if (end - pos < (int) sizeof(int) + val) break; os_memcpy(pos, &val, sizeof(int)); @@ -174,8 +211,7 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, pos += val; } - sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, - sizeof(*from)); + sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, fromlen); os_free(buf); wpa_scan_results_free(res); @@ -184,21 +220,21 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, fail: os_free(buf); wpa_scan_results_free(res); - sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen); } static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, + socklen_t fromlen) { if (iface->drv_priv == NULL) return; if (iface->driver->get_scan_results2) - wpa_priv_get_scan_results2(iface, from); + wpa_priv_get_scan_results2(iface, from, fromlen); else - sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, - sizeof(*from)); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen); } @@ -218,7 +254,7 @@ static void wpa_priv_cmd_authenticate(struct wpa_priv_interface *iface, } auth = buf; - if (sizeof(*auth) + auth->ie_len + auth->sae_data_len > len) { + if (sizeof(*auth) + auth->ie_len + auth->auth_data_len > len) { wpa_printf(MSG_DEBUG, "Authentication request overflow"); return; } @@ -244,9 +280,9 @@ static void wpa_priv_cmd_authenticate(struct wpa_priv_interface *iface, params.ie = (u8 *) (auth + 1); params.ie_len = auth->ie_len; } - if (auth->sae_data_len) { - params.sae_data = ((u8 *) (auth + 1)) + auth->ie_len; - params.sae_data_len = auth->sae_data_len; + if (auth->auth_data_len) { + params.auth_data = ((u8 *) (auth + 1)) + auth->ie_len; + params.auth_data_len = auth->auth_data_len; } res = iface->driver->authenticate(iface->drv_priv, ¶ms); @@ -303,7 +339,7 @@ static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface, static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, socklen_t fromlen) { u8 bssid[ETH_ALEN]; @@ -315,16 +351,16 @@ static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface, goto fail; sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from, - sizeof(*from)); + fromlen); return; fail: - sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen); } static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, socklen_t fromlen) { u8 ssid[sizeof(int) + SSID_MAX_LEN]; int res; @@ -335,17 +371,18 @@ static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface, if (iface->driver->get_ssid == NULL) goto fail; + os_memset(ssid, 0, sizeof(ssid)); res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]); if (res < 0 || res > SSID_MAX_LEN) goto fail; os_memcpy(ssid, &res, sizeof(int)); sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from, - sizeof(*from)); + fromlen); return; fail: - sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen); } @@ -378,7 +415,7 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, socklen_t fromlen) { struct wpa_driver_capa capa; @@ -394,18 +431,19 @@ static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface, capa.extended_capa_mask = NULL; capa.extended_capa_len = 0; sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from, - sizeof(*from)); + fromlen); return; fail: - sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen); } static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { - struct wpa_priv_interface *iface = ctx; + struct wpa_priv_l2 *l2_ctx = ctx; + struct wpa_priv_interface *iface = l2_ctx->parent; struct msghdr msg; struct iovec io[2]; @@ -417,8 +455,8 @@ static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf, os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; msg.msg_iovlen = 2; - msg.msg_name = &iface->l2_addr; - msg.msg_namelen = sizeof(iface->l2_addr); + msg.msg_name = &iface->l2_addr[l2_ctx->idx]; + msg.msg_namelen = iface->l2_addr_len[l2_ctx->idx]; if (sendmsg(iface->fd, &msg, 0) < 0) { wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno)); @@ -426,14 +464,23 @@ static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf, } +static int wpa_priv_allowed_l2_proto(u16 proto) +{ + return proto == ETH_P_EAPOL || proto == ETH_P_RSN_PREAUTH || + proto == ETH_P_80211_ENCAP; +} + + static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface, struct sockaddr_un *from, + socklen_t fromlen, void *buf, size_t len) { int *reg_cmd = buf; u8 own_addr[ETH_ALEN]; int res; u16 proto; + int idx; if (len != 2 * sizeof(int)) { wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu", @@ -442,50 +489,69 @@ static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface, } proto = reg_cmd[0]; - if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH && - proto != ETH_P_80211_ENCAP) { + if (!wpa_priv_allowed_l2_proto(proto)) { wpa_printf(MSG_DEBUG, "Refused l2_packet connection for " "ethertype 0x%x", proto); return; } - if (iface->l2) { - wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " - "instance"); - l2_packet_deinit(iface->l2); - iface->l2 = NULL; + for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) { + if (!iface->l2[idx]) + break; + } + if (idx == WPA_PRIV_MAX_L2) { + wpa_printf(MSG_DEBUG, "No free l2_packet connection found"); + return; } - os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr)); + os_memcpy(&iface->l2_addr[idx], from, fromlen); + iface->l2_addr_len[idx] = fromlen; - iface->l2 = l2_packet_init(iface->ifname, NULL, proto, - wpa_priv_l2_rx, iface, reg_cmd[1]); - if (iface->l2 == NULL) { + iface->l2_ctx[idx].idx = idx; + iface->l2_ctx[idx].parent = iface; + iface->l2[idx] = l2_packet_init(iface->ifname, NULL, proto, + wpa_priv_l2_rx, &iface->l2_ctx[idx], + reg_cmd[1]); + if (!iface->l2[idx]) { wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet " "instance for protocol %d", proto); return; } - if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) { + if (l2_packet_get_own_addr(iface->l2[idx], own_addr) < 0) { wpa_printf(MSG_DEBUG, "Failed to get own address from " "l2_packet"); - l2_packet_deinit(iface->l2); - iface->l2 = NULL; + l2_packet_deinit(iface->l2[idx]); + iface->l2[idx] = NULL; return; } res = sendto(iface->fd, own_addr, ETH_ALEN, 0, - (struct sockaddr *) from, sizeof(*from)); - wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res); + (struct sockaddr *) from, fromlen); + wpa_printf(MSG_DEBUG, "L2 registration[idx=%d]: res=%d", idx, res); } static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface, - struct sockaddr_un *from) + struct sockaddr_un *from, + socklen_t fromlen) { - if (iface->l2) { - l2_packet_deinit(iface->l2); - iface->l2 = NULL; + int idx; + + for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) { + if (iface->l2_addr_len[idx] == fromlen && + os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0) + break; + } + if (idx == WPA_PRIV_MAX_L2) { + wpa_printf(MSG_DEBUG, + "No registered l2_packet socket found for unregister request"); + return; + } + + if (iface->l2[idx]) { + l2_packet_deinit(iface->l2[idx]); + iface->l2[idx] = NULL; } } @@ -493,20 +559,36 @@ static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface, static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface, struct sockaddr_un *from) { - if (iface->l2) - l2_packet_notify_auth_start(iface->l2); + int idx; + + for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) { + if (iface->l2[idx]) + l2_packet_notify_auth_start(iface->l2[idx]); + } } static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface, - struct sockaddr_un *from, + struct sockaddr_un *from, socklen_t fromlen, void *buf, size_t len) { u8 *dst_addr; u16 proto; int res; + int idx; - if (iface->l2 == NULL) + for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) { + if (iface->l2_addr_len[idx] == fromlen && + os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0) + break; + } + if (idx == WPA_PRIV_MAX_L2) { + wpa_printf(MSG_DEBUG, + "No registered l2_packet socket found for send request"); + return; + } + + if (iface->l2[idx] == NULL) return; if (len < ETH_ALEN + 2) { @@ -518,15 +600,15 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface, dst_addr = buf; os_memcpy(&proto, buf + ETH_ALEN, 2); - if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { + if (!wpa_priv_allowed_l2_proto(proto)) { wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype " "0x%x", proto); return; } - res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2, - len - ETH_ALEN - 2); - wpa_printf(MSG_DEBUG, "L2 send: res=%d", res); + res = l2_packet_send(iface->l2[idx], dst_addr, proto, + buf + ETH_ALEN + 2, len - ETH_ALEN - 2); + wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res); } @@ -571,7 +653,7 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) switch (cmd) { case PRIVSEP_CMD_REGISTER: - wpa_priv_cmd_register(iface, &from); + wpa_priv_cmd_register(iface, &from, fromlen); break; case PRIVSEP_CMD_UNREGISTER: wpa_priv_cmd_unregister(iface, &from); @@ -580,34 +662,35 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) wpa_priv_cmd_scan(iface, cmd_buf, cmd_len); break; case PRIVSEP_CMD_GET_SCAN_RESULTS: - wpa_priv_cmd_get_scan_results(iface, &from); + wpa_priv_cmd_get_scan_results(iface, &from, fromlen); break; case PRIVSEP_CMD_ASSOCIATE: wpa_priv_cmd_associate(iface, cmd_buf, cmd_len); break; case PRIVSEP_CMD_GET_BSSID: - wpa_priv_cmd_get_bssid(iface, &from); + wpa_priv_cmd_get_bssid(iface, &from, fromlen); break; case PRIVSEP_CMD_GET_SSID: - wpa_priv_cmd_get_ssid(iface, &from); + wpa_priv_cmd_get_ssid(iface, &from, fromlen); break; case PRIVSEP_CMD_SET_KEY: wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len); break; case PRIVSEP_CMD_GET_CAPA: - wpa_priv_cmd_get_capa(iface, &from); + wpa_priv_cmd_get_capa(iface, &from, fromlen); break; case PRIVSEP_CMD_L2_REGISTER: - wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len); + wpa_priv_cmd_l2_register(iface, &from, fromlen, + cmd_buf, cmd_len); break; case PRIVSEP_CMD_L2_UNREGISTER: - wpa_priv_cmd_l2_unregister(iface, &from); + wpa_priv_cmd_l2_unregister(iface, &from, fromlen); break; case PRIVSEP_CMD_L2_NOTIFY_AUTH_START: wpa_priv_cmd_l2_notify_auth_start(iface, &from); break; case PRIVSEP_CMD_L2_SEND: - wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len); + wpa_priv_cmd_l2_send(iface, &from, fromlen, cmd_buf, cmd_len); break; case PRIVSEP_CMD_SET_COUNTRY: pos = cmd_buf; @@ -625,8 +708,14 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) { - if (iface->drv_priv && iface->driver->deinit) - iface->driver->deinit(iface->drv_priv); + int i; + + if (iface->drv_priv) { + if (iface->driver->deinit) + iface->driver->deinit(iface->drv_priv); + if (iface->drv_global_priv) + iface->driver->global_deinit(iface->drv_global_priv); + } if (iface->fd >= 0) { eloop_unregister_read_sock(iface->fd); @@ -634,8 +723,10 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) unlink(iface->sock_name); } - if (iface->l2) - l2_packet_deinit(iface->l2); + for (i = 0; i < WPA_PRIV_MAX_L2; i++) { + if (iface->l2[i]) + l2_packet_deinit(iface->l2[i]); + } os_free(iface->ifname); os_free(iface->driver_name); @@ -777,7 +868,7 @@ static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event, msg.msg_iov = io; msg.msg_iovlen = data ? 2 : 1; msg.msg_name = &iface->drv_addr; - msg.msg_namelen = sizeof(iface->drv_addr); + msg.msg_namelen = iface->drv_addr_len; if (sendmsg(iface->fd, &msg, 0) < 0) { wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s", @@ -796,7 +887,7 @@ static void wpa_priv_send_auth(struct wpa_priv_interface *iface, struct privsep_event_auth *auth; u8 *buf, *pos; - buf = os_malloc(buflen); + buf = os_zalloc(buflen); if (buf == NULL) return; @@ -990,12 +1081,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, &data->pmkid_candidate, sizeof(struct pmkid_candidate)); break; - case EVENT_STKSTART: - if (data == NULL) - return; - wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART, - &data->stkstart.peer, ETH_ALEN); - break; case EVENT_FT_RESPONSE: wpa_priv_send_ft_response(iface, data); break; @@ -1061,7 +1146,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, msg.msg_iov = io; msg.msg_iovlen = 3; msg.msg_name = &iface->drv_addr; - msg.msg_namelen = sizeof(iface->drv_addr); + msg.msg_namelen = iface->drv_addr_len; if (sendmsg(iface->fd, &msg, 0) < 0) wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s", @@ -1099,7 +1184,7 @@ static void wpa_priv_fd_workaround(void) static void usage(void) { printf("wpa_priv v" VERSION_STR "\n" - "Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> and " + "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and " "contributors\n" "\n" "usage:\n" diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/contrib/wpa/wpa_supplicant/wpa_supplicant.c index 7361ee96d1df..96a3691cf3cf 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant.c +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - * Copyright (c) 2003-2016, 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. @@ -38,6 +38,8 @@ #include "common/wpa_ctrl.h" #include "common/ieee802_11_defs.h" #include "common/hw_features_common.h" +#include "common/gas_server.h" +#include "common/dpp.h" #include "p2p/p2p.h" #include "fst/fst.h" #include "blacklist.h" @@ -59,10 +61,15 @@ #include "wnm_sta.h" #include "wpas_kay.h" #include "mesh.h" +#include "dpp_supplicant.h" +#ifdef CONFIG_MESH +#include "ap/ap_config.h" +#include "ap/hostapd.h" +#endif /* CONFIG_MESH */ const char *const wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors"; const char *const wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -112,6 +119,13 @@ const char *const wpa_supplicant_full_license5 = "\n"; #endif /* CONFIG_NO_STDOUT_DEBUG */ + +static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx); +#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) +static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s); +#endif /* CONFIG_FILS && IEEE8021X_EAPOL */ + + /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -230,10 +244,30 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec " "%d usec", sec, usec); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); + wpa_s->last_auth_timeout_sec = sec; eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL); } +/* + * wpas_auth_timeout_restart - Restart and change timeout for authentication + * @wpa_s: Pointer to wpa_supplicant data + * @sec_diff: difference in seconds applied to original timeout value + */ +void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff) +{ + int new_sec = wpa_s->last_auth_timeout_sec + sec_diff; + + if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Authentication timeout restart: %d sec", new_sec); + eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); + eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout, + wpa_s, NULL); + } +} + + /** * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout * @wpa_s: Pointer to wpa_supplicant data @@ -247,6 +281,9 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout"); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); wpa_blacklist_del(wpa_s, wpa_s->bssid); + os_free(wpa_s->last_con_fail_realm); + wpa_s->last_con_fail_realm = NULL; + wpa_s->last_con_fail_realm_len = 0; } @@ -329,7 +366,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); - ieee802_1x_alloc_kay_sm(wpa_s, ssid); +#ifdef CONFIG_MACSEC + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set) + ieee802_1x_create_preshared_mka(wpa_s, ssid); + else + ieee802_1x_alloc_kay_sm(wpa_s, ssid); +#endif /* CONFIG_MACSEC */ #endif /* IEEE8021X_EAPOL */ } @@ -403,18 +445,32 @@ void free_hw_features(struct wpa_supplicant *wpa_s) } -static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s) +void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s) { struct wpa_bss_tmp_disallowed *bss, *prev; dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed, struct wpa_bss_tmp_disallowed, list) { + eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss); dl_list_del(&bss->list); os_free(bss); } } +void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s) +{ + struct fils_hlp_req *req; + + while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req, + list)) != NULL) { + dl_list_del(&req->list); + wpabuf_free(req->pkt); + os_free(req); + } +} + + static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { int i; @@ -434,6 +490,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) #ifdef CONFIG_TESTING_OPTIONS l2_packet_deinit(wpa_s->l2_test); wpa_s->l2_test = NULL; + os_free(wpa_s->get_pref_freq_list_override); + 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; #endif /* CONFIG_TESTING_OPTIONS */ if (wpa_s->conf != NULL) { @@ -448,6 +508,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->confanother); wpa_s->confanother = NULL; + os_free(wpa_s->last_con_fail_realm); + wpa_s->last_con_fail_realm = NULL; + wpa_s->last_con_fail_realm_len = 0; + wpa_sm_set_eapol(wpa_s->wpa, NULL); eapol_sm_deinit(wpa_s->eapol); wpa_s->eapol = NULL; @@ -506,6 +570,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->manual_scan_freqs); wpa_s->manual_scan_freqs = NULL; + os_free(wpa_s->select_network_scan_freqs); + wpa_s->select_network_scan_freqs = NULL; os_free(wpa_s->manual_sched_scan_freqs); wpa_s->manual_sched_scan_freqs = NULL; @@ -524,6 +590,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) radio_remove_works(wpa_s, "gas-query", 0); gas_query_deinit(wpa_s->gas); wpa_s->gas = NULL; + gas_server_deinit(wpa_s->gas_server); + wpa_s->gas_server = NULL; free_hw_features(wpa_s); @@ -580,6 +648,34 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpabuf_free(wpa_s->lci); wpa_s->lci = NULL; + wpas_clear_beacon_rep_data(wpa_s); + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + { + struct external_pmksa_cache *entry; + + while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache, + struct external_pmksa_cache, + list)) != NULL) { + dl_list_del(&entry->list); + os_free(entry->pmksa_cache); + os_free(entry); + } + } +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + wpas_flush_fils_hlp_req(wpa_s); + + wpabuf_free(wpa_s->ric_ies); + wpa_s->ric_ies = NULL; + +#ifdef CONFIG_DPP + wpas_dpp_deinit(wpa_s); + dpp_global_deinit(wpa_s->dpp); + wpa_s->dpp = NULL; +#endif /* CONFIG_DPP */ } @@ -753,6 +849,23 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_supplicant_state_txt(state)); + if (state == WPA_COMPLETED && + os_reltime_initialized(&wpa_s->roam_start)) { + os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time); + wpa_s->roam_start.sec = 0; + wpa_s->roam_start.usec = 0; + wpas_notify_auth_changed(wpa_s); + wpas_notify_roam_time(wpa_s); + wpas_notify_roam_complete(wpa_s); + } else if (state == WPA_DISCONNECTED && + os_reltime_initialized(&wpa_s->roam_start)) { + wpa_s->roam_start.sec = 0; + wpa_s->roam_start.usec = 0; + wpa_s->roam_time.sec = 0; + wpa_s->roam_time.usec = 0; + wpas_notify_roam_complete(wpa_s); + } + if (state == WPA_INTERFACE_DISABLED) { /* Assure normal scan when interface is restored */ wpa_s->normal_scans = 0; @@ -793,12 +906,24 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, if (state == WPA_COMPLETED && wpa_s->new_connection) { struct wpa_ssid *ssid = wpa_s->current_ssid; + int fils_hlp_sent = 0; + +#ifdef CONFIG_SME + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + wpa_auth_alg_fils(wpa_s->sme.auth_alg)) + fils_hlp_sent = 1; +#endif /* CONFIG_SME */ + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + wpa_auth_alg_fils(wpa_s->auth_alg)) + fils_hlp_sent = 1; + #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to " - MACSTR " completed [id=%d id_str=%s]", + MACSTR " completed [id=%d id_str=%s%s]", MAC2STR(wpa_s->bssid), ssid ? ssid->id : -1, - ssid && ssid->id_str ? ssid->id_str : ""); + ssid && ssid->id_str ? ssid->id_str : "", + fils_hlp_sent ? " FILS_HLP_SENT" : ""); #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ wpas_clear_temp_disabled(wpa_s, ssid, 1); wpa_blacklist_clear(wpa_s); @@ -813,6 +938,11 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpas_p2p_completed(wpa_s); sme_sched_obss_scan(wpa_s, 1); + +#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) + if (!fils_hlp_sent && ssid && ssid->eap.erp) + wpas_update_fils_connect_params(wpa_s); +#endif /* CONFIG_FILS && IEEE8021X_EAPOL */ } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING || state == WPA_ASSOCIATED) { wpa_s->new_connection = 1; @@ -831,7 +961,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_supplicant_stop_bgscan(wpa_s); #endif /* CONFIG_BGSCAN */ - if (state == WPA_AUTHENTICATING) + if (state > WPA_SCANNING) wpa_supplicant_stop_autoscan(wpa_s); if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) @@ -927,7 +1057,13 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) "file '%s' - exiting", wpa_s->confname); return -1; } - wpa_config_read(wpa_s->confanother, conf); + if (wpa_s->confanother && + !wpa_config_read(wpa_s->confanother, conf)) { + wpa_msg(wpa_s, MSG_ERROR, + "Failed to parse the configuration file '%s' - exiting", + wpa_s->confanother); + return -1; + } conf->changed_parameters = (unsigned int) -1; @@ -953,7 +1089,9 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) * TODO: should notify EAPOL SM about changes in opensc_engine_path, * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers. */ - if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { + 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) { /* * Clear forced success to clear EAP state for next * authentication. @@ -1054,6 +1192,18 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s, } +static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie, + int freq) +{ + if (!ie->has_group) + ie->group_cipher = wpa_default_rsn_cipher(freq); + if (!ie->has_pairwise) + ie->pairwise_cipher = wpa_default_rsn_cipher(freq); + return (ie->group_cipher & ssid->group_cipher) && + (ie->pairwise_cipher & ssid->pairwise_cipher); +} + + /** * wpa_supplicant_set_suites - Set authentication and encryption parameters * @wpa_s: Pointer to wpa_supplicant data @@ -1085,8 +1235,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) && wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && - (ie.group_cipher & ssid->group_cipher) && - (ie.pairwise_cipher & ssid->pairwise_cipher) && + matching_ciphers(ssid, &ie, bss->freq) && (ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0"); proto = WPA_PROTO_RSN; @@ -1098,14 +1247,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0"); proto = WPA_PROTO_WPA; #ifdef CONFIG_HS20 - } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) { + } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) && + wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 && + (ie.group_cipher & ssid->group_cipher) && + (ie.pairwise_cipher & ssid->pairwise_cipher) && + (ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN"); - /* TODO: parse OSEN element */ - os_memset(&ie, 0, sizeof(ie)); - ie.group_cipher = WPA_CIPHER_CCMP; - ie.pairwise_cipher = WPA_CIPHER_CCMP; - ie.key_mgmt = WPA_KEY_MGMT_OSEN; proto = WPA_PROTO_OSEN; + } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) && + wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && + (ie.group_cipher & ssid->group_cipher) && + (ie.pairwise_cipher & ssid->pairwise_cipher) && + (ie.key_mgmt & ssid->key_mgmt)) { + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)"); + proto = WPA_PROTO_RSN; #endif /* CONFIG_HS20 */ } else if (bss) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN"); @@ -1157,10 +1312,35 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, ie.pairwise_cipher = ssid->pairwise_cipher; ie.key_mgmt = ssid->key_mgmt; #ifdef CONFIG_IEEE80211W - ie.mgmt_group_cipher = - ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ? - WPA_CIPHER_AES_128_CMAC : 0; + ie.mgmt_group_cipher = 0; + if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + if (ssid->group_mgmt_cipher & + WPA_CIPHER_BIP_GMAC_256) + ie.mgmt_group_cipher = + WPA_CIPHER_BIP_GMAC_256; + else if (ssid->group_mgmt_cipher & + WPA_CIPHER_BIP_CMAC_256) + ie.mgmt_group_cipher = + WPA_CIPHER_BIP_CMAC_256; + else if (ssid->group_mgmt_cipher & + WPA_CIPHER_BIP_GMAC_128) + ie.mgmt_group_cipher = + WPA_CIPHER_BIP_GMAC_128; + else + 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 && + !bss_wpa && !bss_rsn && !bss_osen) { + wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); + wpa_s->wpa_proto = 0; + *wpa_ie_len = 0; + return 0; + } +#endif /* CONFIG_OWE */ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites " "based on configuration"); } else @@ -1195,6 +1375,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_s->pairwise_cipher = WPA_CIPHER_NONE; #else /* CONFIG_NO_WPA */ sel = ie.group_cipher & ssid->group_cipher; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x", + ie.group_cipher, ssid->group_cipher, sel); wpa_s->group_cipher = wpa_pick_group_cipher(sel); if (wpa_s->group_cipher < 0) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group " @@ -1205,6 +1388,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_cipher_txt(wpa_s->group_cipher)); sel = ie.pairwise_cipher & ssid->pairwise_cipher; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x", + ie.pairwise_cipher, ssid->pairwise_cipher, sel); wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1); if (wpa_s->pairwise_cipher < 0) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise " @@ -1216,11 +1402,29 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_WPA */ sel = ie.key_mgmt & ssid->key_mgmt; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x", + ie.key_mgmt, ssid->key_mgmt, sel); #ifdef CONFIG_SAE if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE); #endif /* CONFIG_SAE */ if (0) { +#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_SHA384 + } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using KEY_MGMT FT/802.1X-SHA384"); + if (pmksa_cache_get_current(wpa_s->wpa)) { + /* PMKSA caching with FT is not fully functional, so + * disable the case for now. */ + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: Disable PMKSA caching for FT/802.1X connection"); + pmksa_cache_clear_current(wpa_s->wpa); + } +#endif /* CONFIG_SHA384 */ +#endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_SUITEB192 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; @@ -1233,22 +1437,52 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X with Suite B"); #endif /* CONFIG_SUITEB */ +#ifdef CONFIG_FILS +#ifdef CONFIG_IEEE80211R + } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384"); + } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256"); +#endif /* CONFIG_IEEE80211R */ + } else if (sel & WPA_KEY_MGMT_FILS_SHA384) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384"); + } else if (sel & WPA_KEY_MGMT_FILS_SHA256) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256; + 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) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X"); - } else if (sel & WPA_KEY_MGMT_FT_PSK) { - wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK"); + if (pmksa_cache_get_current(wpa_s->wpa)) { + /* PMKSA caching with FT is not fully functional, so + * disable the case for now. */ + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: Disable PMKSA caching for FT/802.1X connection"); + pmksa_cache_clear_current(wpa_s->wpa); + } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_DPP + } else if (sel & WPA_KEY_MGMT_DPP) { + wpa_s->key_mgmt = WPA_KEY_MGMT_DPP; + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP"); +#endif /* CONFIG_DPP */ #ifdef CONFIG_SAE - } else if (sel & WPA_KEY_MGMT_SAE) { - wpa_s->key_mgmt = WPA_KEY_MGMT_SAE; - wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE"); } else if (sel & WPA_KEY_MGMT_FT_SAE) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE; wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE"); + } else if (sel & WPA_KEY_MGMT_SAE) { + wpa_s->key_mgmt = WPA_KEY_MGMT_SAE; + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE"); #endif /* CONFIG_SAE */ +#ifdef CONFIG_IEEE80211R + } else if (sel & WPA_KEY_MGMT_FT_PSK) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK"); +#endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) { wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; @@ -1273,6 +1507,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN; wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN"); #endif /* CONFIG_HS20 */ +#ifdef CONFIG_OWE + } else if (sel & WPA_KEY_MGMT_OWE) { + wpa_s->key_mgmt = WPA_KEY_MGMT_OWE; + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE"); +#endif /* CONFIG_OWE */ } else { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select " "authenticated key management type"); @@ -1286,9 +1525,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211W sel = ie.mgmt_group_cipher; + if (ssid->group_mgmt_cipher) + sel &= ssid->group_mgmt_cipher; if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION || !(ie.capabilities & WPA_CAPABILITY_MFPC)) sel = 0; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x", + ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel); if (sel & WPA_CIPHER_AES_128_CMAC) { wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " @@ -1314,23 +1558,44 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, wpas_get_ssid_pmf(wpa_s, ssid)); #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv); +#endif /* CONFIG_OCV */ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE"); return -1; } - if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) { + if (0) { +#ifdef CONFIG_DPP + } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) { + /* Use PMK from DPP network introduction (PMKSA entry) */ + wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); +#endif /* CONFIG_DPP */ + } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) { int psk_set = 0; + int sae_only; + + sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256)) == 0; - if (ssid->psk_set) { + if (ssid->psk_set && !sae_only) { + wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)", + ssid->psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, NULL); psk_set = 1; } + + if (wpa_key_mgmt_sae(ssid->key_mgmt) && + (ssid->sae_password || ssid->passphrase)) + psk_set = 1; + #ifndef CONFIG_NO_PBKDF2 if (bss && ssid->bssid_set && ssid->ssid_len == 0 && - ssid->passphrase) { + ssid->passphrase && !sae_only) { u8 psk[PMK_LEN]; pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len, 4096, psk, PMK_LEN); @@ -1342,7 +1607,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_NO_PBKDF2 */ #ifdef CONFIG_EXT_PASSWORD - if (ssid->ext_psk) { + if (ssid->ext_psk && !sae_only) { struct wpabuf *pw = ext_password_get(wpa_s->ext_pw, ssid->ext_psk); char pw_str[64 + 1]; @@ -1388,6 +1653,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, ext_password_free(pw); return -1; } + wpa_hexdump_key(MSG_MSGDUMP, + "PSK (from external PSK)", + psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL); psk_set = 1; @@ -1408,8 +1676,15 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, if (!psk_set) { wpa_msg(wpa_s, MSG_INFO, "No PSK available for association"); + wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE"); return -1; } +#ifdef CONFIG_OWE + } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) { + /* OWE Diffie-Hellman exchange in (Re)Association + * Request/Response frames set the PMK, so do not override it + * here. */ +#endif /* CONFIG_OWE */ } else wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); @@ -1425,6 +1700,10 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) case 0: /* Bits 0-7 */ break; case 1: /* Bits 8-15 */ + if (wpa_s->conf->coloc_intf_reporting) { + /* Bit 13 - Collocated Interference Reporting */ + *pos |= 0x20; + } break; case 2: /* Bits 16-23 */ #ifdef CONFIG_WNM @@ -1443,7 +1722,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) break; case 4: /* Bits 32-39 */ #ifdef CONFIG_INTERWORKING - if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING) + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING) *pos |= 0x01; /* Bit 32 - QoS Map */ #endif /* CONFIG_INTERWORKING */ break; @@ -1466,6 +1745,12 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) if (wpa_s->conf->ftm_initiator) *pos |= 0x80; /* Bit 71 - FTM initiator */ break; + case 9: /* Bits 72-79 */ +#ifdef CONFIG_FILS + if (!wpa_s->disable_fils) + *pos |= 0x01; +#endif /* CONFIG_FILS */ + break; } } @@ -1473,11 +1758,8 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen) { u8 *pos = buf; - u8 len = 6, i; + u8 len = 10, i; - if (len < 9 && - (wpa_s->conf->ftm_initiator || wpa_s->conf->ftm_responder)) - len = 9; if (len < wpa_s->extended_capa_len) len = wpa_s->extended_capa_len; if (buflen < (size_t) len + 2) { @@ -1665,6 +1947,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wmm_ac_clear_saved_tspecs(wpa_s); wpa_s->reassoc_same_bss = 0; wpa_s->reassoc_same_ess = 0; +#ifdef CONFIG_TESTING_OPTIONS + wpa_s->testing_resend_assoc = 0; +#endif /* CONFIG_TESTING_OPTIONS */ if (wpa_s->last_ssid == ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS"); @@ -1672,12 +1957,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, if (wpa_s->current_bss && wpa_s->current_bss == bss) { wmm_ac_save_tspecs(wpa_s); wpa_s->reassoc_same_bss = 1; + } else if (wpa_s->current_bss && wpa_s->current_bss != bss) { + os_get_reltime(&wpa_s->roam_start); } - } else if (rand_style > 0) { + } + + if (rand_style > 0 && !wpa_s->reassoc_same_ess) { if (wpas_update_random_addr(wpa_s, rand_style) < 0) return; wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); - } else if (wpa_s->mac_addr_changed) { + } else if (rand_style == 0 && wpa_s->mac_addr_changed) { if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) { wpa_msg(wpa_s, MSG_INFO, "Could not restore permanent MAC address"); @@ -1696,6 +1985,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); wpa_s->ibss_rsn = NULL; +#else /* CONFIG_IBSS_RSN */ + if (ssid->mode == WPAS_MODE_IBSS && + !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) { + wpa_msg(wpa_s, MSG_INFO, + "IBSS RSN not supported in the build"); + return; + } #endif /* CONFIG_IBSS_RSN */ if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO || @@ -1737,6 +2033,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d", wpa_ssid_txt(ssid->ssid, ssid->ssid_len), ssid->id); + wpas_notify_mesh_group_started(wpa_s, ssid); #else /* CONFIG_MESH */ wpa_msg(wpa_s, MSG_ERROR, "mesh mode support not included in the build"); @@ -1744,6 +2041,20 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + /* + * Set WPA state machine configuration to match the selected network now + * so that the information is available before wpas_start_assoc_cb() + * gets called. This is needed at least for RSN pre-authentication where + * candidate APs are added to a list based on scan result processing + * before completion of the first association. + */ + wpa_supplicant_rsn_supp_set_config(wpa_s, ssid); + +#ifdef CONFIG_DPP + if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0) + return; +#endif /* CONFIG_DPP */ + #ifdef CONFIG_TDLS if (bss) wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1), @@ -1766,6 +2077,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } +#ifdef CONFIG_SME + if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) { + /* Clear possibly set auth_alg, if any, from last attempt. */ + wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN; + } +#endif /* CONFIG_SME */ + wpas_abort_ongoing_scan(wpa_s); cwork = os_zalloc(sizeof(*cwork)); @@ -1797,11 +2115,6 @@ static int drv_supports_vht(struct wpa_supplicant *wpa_s, u8 channel; int i; -#ifdef CONFIG_HT_OVERRIDES - if (ssid->disable_ht) - return 0; -#endif /* CONFIG_HT_OVERRIDES */ - hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel); if (hw_mode == NUM_HOSTAPD_MODES) return 0; @@ -1914,9 +2227,14 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) return; + freq->channel = pri_chan->chan; + #ifdef CONFIG_HT_OVERRIDES - if (ssid->disable_ht40) - return; + if (ssid->disable_ht40) { + if (ssid->disable_vht) + return; + goto skip_ht40; + } #endif /* CONFIG_HT_OVERRIDES */ /* Check/setup HT40+/HT40- */ @@ -1941,8 +2259,6 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) return; - freq->channel = pri_chan->chan; - if (ht40 == -1) { if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS)) return; @@ -1986,6 +2302,9 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, wpa_scan_results_free(scan_res); } +#ifdef CONFIG_HT_OVERRIDES +skip_ht40: +#endif /* CONFIG_HT_OVERRIDES */ wpa_printf(MSG_DEBUG, "IBSS/mesh: setup freq channel %d, sec_channel_offset %d", freq->channel, freq->sec_channel_offset); @@ -2000,6 +2319,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, vht_freq = *freq; +#ifdef CONFIG_VHT_OVERRIDES + if (ssid->disable_vht) { + freq->vht_enabled = 0; + return; + } +#endif /* CONFIG_VHT_OVERRIDES */ + vht_freq.vht_enabled = vht_supported(mode); if (!vht_freq.vht_enabled) return; @@ -2068,6 +2394,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; seg0 = 114; } + } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_USE_HT) { + chwidth = VHT_CHANWIDTH_USE_HT; + seg0 = vht80[j] + 2; +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht40) + seg0 = 0; +#endif /* CONFIG_HT_OVERRIDES */ } if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq, @@ -2084,147 +2417,177 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, } -static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) +#ifdef CONFIG_FILS +static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf, + size_t ie_buf_len) { - struct wpa_connect_work *cwork = work->ctx; - struct wpa_bss *bss = cwork->bss; - struct wpa_ssid *ssid = cwork->ssid; - struct wpa_supplicant *wpa_s = work->wpa_s; - u8 wpa_ie[200]; - size_t wpa_ie_len; - int use_crypt, ret, i, bssid_changed; - int algs = WPA_AUTH_ALG_OPEN; - unsigned int cipher_pairwise, cipher_group; - struct wpa_driver_associate_params params; - int wep_keys_set = 0; - int assoc_failed = 0; - struct wpa_ssid *old_ssid; - u8 prev_bssid[ETH_ALEN]; -#ifdef CONFIG_HT_OVERRIDES - struct ieee80211_ht_capabilities htcaps; - struct ieee80211_ht_capabilities htcaps_mask; -#endif /* CONFIG_HT_OVERRIDES */ -#ifdef CONFIG_VHT_OVERRIDES - struct ieee80211_vht_capabilities vhtcaps; - struct ieee80211_vht_capabilities vhtcaps_mask; -#endif /* CONFIG_VHT_OVERRIDES */ -#ifdef CONFIG_MBO - const u8 *mbo = NULL; -#endif /* CONFIG_MBO */ + struct fils_hlp_req *req; + size_t rem_len, hdr_len, hlp_len, len, ie_len = 0; + const u8 *pos; + u8 *buf = ie_buf; - if (deinit) { - if (work->started) { - wpa_s->connect_work = NULL; + dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req, + list) { + rem_len = ie_buf_len - ie_len; + pos = wpabuf_head(req->pkt); + hdr_len = 1 + 2 * ETH_ALEN + 6; + hlp_len = wpabuf_len(req->pkt); - /* cancel possible auth. timeout */ - eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, - NULL); + if (rem_len < 2 + hdr_len + hlp_len) { + wpa_printf(MSG_ERROR, + "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu", + (unsigned long) rem_len, + (unsigned long) (2 + hdr_len + hlp_len)); + break; + } + + len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len; + /* Element ID */ + *buf++ = WLAN_EID_EXTENSION; + /* Length */ + *buf++ = len; + /* Element ID Extension */ + *buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER; + /* Destination MAC address */ + os_memcpy(buf, req->dst, ETH_ALEN); + buf += ETH_ALEN; + /* Source MAC address */ + os_memcpy(buf, wpa_s->own_addr, ETH_ALEN); + buf += ETH_ALEN; + /* LLC/SNAP Header */ + os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6); + buf += 6; + /* HLP Packet */ + os_memcpy(buf, pos, len - hdr_len); + buf += len - hdr_len; + pos += len - hdr_len; + + hlp_len -= len - hdr_len; + ie_len += 2 + len; + rem_len -= 2 + len; + + while (hlp_len) { + len = (hlp_len > 255) ? 255 : hlp_len; + if (rem_len < 2 + len) + break; + *buf++ = WLAN_EID_FRAGMENT; + *buf++ = len; + os_memcpy(buf, pos, len); + buf += len; + pos += len; + + hlp_len -= len; + ie_len += 2 + len; + rem_len -= 2 + len; } - wpas_connect_work_free(cwork); - return; } - wpa_s->connect_work = work; + return ie_len; +} - if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) || - wpas_network_disabled(wpa_s, ssid)) { - wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt"); - wpas_connect_work_done(wpa_s); - return; - } - os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN); - os_memset(¶ms, 0, sizeof(params)); - wpa_s->reassociate = 0; - wpa_s->eap_expected_failure = 0; - if (bss && - (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) { -#ifdef CONFIG_IEEE80211R - const u8 *ie, *md = NULL; -#endif /* CONFIG_IEEE80211R */ - wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR - " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid), - wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq); - 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); -#ifdef CONFIG_IEEE80211R - ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); - if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) - md = ie + 2; - wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0); - if (md) { - /* Prepare for the next transition */ - wpa_ft_prepare_auth_request(wpa_s->wpa, ie); - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_WPS - } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) && - wpa_s->conf->ap_scan == 2 && - (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { - /* Use ap_scan==1 style network selection to find the network - */ - wpas_connect_work_done(wpa_s); - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_s->reassociate = 1; - wpa_supplicant_req_scan(wpa_s, 0, 0); - return; -#endif /* CONFIG_WPS */ - } else { - wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - if (bss) - os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); - else - os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); - } - if (!wpa_s->pno) - wpa_supplicant_cancel_sched_scan(wpa_s); +int wpa_is_fils_supported(struct wpa_supplicant *wpa_s) +{ + return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) || + (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD))); +} - wpa_supplicant_cancel_scan(wpa_s); - /* 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); +int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_FILS_SK_PFS + return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS); +#else /* CONFIG_FILS_SK_PFS */ + return 0; +#endif /* CONFIG_FILS_SK_PFS */ +} -#ifdef IEEE8021X_EAPOL - if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - if (ssid->leap) { - if (ssid->non_leap == 0) - algs = WPA_AUTH_ALG_LEAP; - else - algs |= WPA_AUTH_ALG_LEAP; - } +#endif /* CONFIG_FILS */ + + +static u8 * wpas_populate_assoc_ies( + struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params, + enum wpa_drv_update_connect_params_mask *mask) +{ + u8 *wpa_ie; + size_t max_wpa_ie_len = 500; + size_t wpa_ie_len; + int algs = WPA_AUTH_ALG_OPEN; +#ifdef CONFIG_MBO + const u8 *mbo_ie; +#endif +#ifdef CONFIG_SAE + int sae_pmksa_cached = 0; +#endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + const u8 *realm, *username, *rrk; + size_t realm_len, username_len, rrk_len; + u16 next_seq_num; + struct fils_hlp_req *req; + + dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req, + list) { + max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) + + 2 + 2 * wpabuf_len(req->pkt) / 255; } -#endif /* IEEE8021X_EAPOL */ - wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs); - if (ssid->auth_alg) { - algs = ssid->auth_alg; - wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: " - "0x%x", algs); +#endif /* CONFIG_FILS */ + + wpa_ie = os_malloc(max_wpa_ie_len); + if (!wpa_ie) { + wpa_printf(MSG_ERROR, + "Failed to allocate connect IE buffer for %lu bytes", + (unsigned long) max_wpa_ie_len); + return NULL; } if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || wpa_bss_get_ie(bss, WLAN_EID_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt)) { int try_opportunistic; + const u8 *cache_id = NULL; + try_opportunistic = (ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching) && (ssid->proto & WPA_PROTO_RSN); +#ifdef CONFIG_FILS + if (wpa_key_mgmt_fils(ssid->key_mgmt)) + cache_id = wpa_bss_get_fils_cache_id(bss); +#endif /* CONFIG_FILS */ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, - ssid, try_opportunistic) == 0) + ssid, try_opportunistic, + cache_id, 0) == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol); - wpa_ie_len = sizeof(wpa_ie); +#ifdef CONFIG_SAE + sae_pmksa_cached = 1; +#endif /* CONFIG_SAE */ + } + wpa_ie_len = max_wpa_ie_len; if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_ie, &wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites"); - wpas_connect_work_done(wpa_s); - return; + os_free(wpa_ie); + return NULL; } +#ifdef CONFIG_HS20 + } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) && + (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) { + /* No PMKSA caching, but otherwise similar to RSN/WPA */ + wpa_ie_len = max_wpa_ie_len; + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, + wpa_ie, &wpa_ie_len)) { + wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " + "key management and encryption suites"); + os_free(wpa_ie); + return NULL; + } +#endif /* CONFIG_HS20 */ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { /* @@ -2236,20 +2599,20 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpa_ie_len = 0; wpa_s->wpa_proto = 0; } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { - wpa_ie_len = sizeof(wpa_ie); + wpa_ie_len = max_wpa_ie_len; if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, wpa_ie, &wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites (no " "scan results)"); - wpas_connect_work_done(wpa_s); - return; + os_free(wpa_ie); + return NULL; } #ifdef CONFIG_WPS } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { struct wpabuf *wps_ie; wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid)); - if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) { + if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) { wpa_ie_len = wpabuf_len(wps_ie); os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len); } else @@ -2257,9 +2620,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpabuf_free(wps_ie); wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY)) - params.wps = WPS_MODE_PRIVACY; + params->wps = WPS_MODE_PRIVACY; else - params.wps = WPS_MODE_OPEN; + params->wps = WPS_MODE_OPEN; wpa_s->wpa_proto = 0; #endif /* CONFIG_WPS */ } else { @@ -2268,13 +2631,69 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpa_s->wpa_proto = 0; } +#ifdef IEEE8021X_EAPOL + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + if (ssid->leap) { + if (ssid->non_leap == 0) + algs = WPA_AUTH_ALG_LEAP; + else + algs |= WPA_AUTH_ALG_LEAP; + } + } + +#ifdef CONFIG_FILS + /* Clear FILS association */ + wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0); + + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) && + ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) && + eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username, + &username_len, &realm, &realm_len, + &next_seq_num, &rrk, &rrk_len) == 0 && + (!wpa_s->last_con_fail_realm || + wpa_s->last_con_fail_realm_len != realm_len || + os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) { + algs = WPA_AUTH_ALG_FILS; + params->fils_erp_username = username; + params->fils_erp_username_len = username_len; + params->fils_erp_realm = realm; + params->fils_erp_realm_len = realm_len; + params->fils_erp_next_seq_num = next_seq_num; + params->fils_erp_rrk = rrk; + params->fils_erp_rrk_len = rrk_len; + + if (mask) + *mask |= WPA_DRV_UPDATE_FILS_ERP_INFO; + } +#endif /* CONFIG_FILS */ +#endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_SAE + if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) + algs = WPA_AUTH_ALG_SAE; +#endif /* CONFIG_SAE */ + + wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs); + if (ssid->auth_alg) { + algs = ssid->auth_alg; + wpa_dbg(wpa_s, MSG_DEBUG, + "Overriding auth_alg selection: 0x%x", algs); + } + +#ifdef CONFIG_SAE + if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt"); + algs = WPA_AUTH_ALG_OPEN; + } +#endif /* CONFIG_SAE */ + #ifdef CONFIG_P2P if (wpa_s->global->p2p) { u8 *pos; size_t len; int res; pos = wpa_ie + wpa_ie_len; - len = sizeof(wpa_ie) - wpa_ie_len; + len = max_wpa_ie_len - wpa_ie_len; res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, ssid->p2p_group); if (res >= 0) @@ -2299,21 +2718,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info)); #endif /* CONFIG_P2P */ -#ifdef CONFIG_MBO if (bss) { - mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); - if (mbo) { - int len; - - len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq, - wpa_ie + wpa_ie_len, - sizeof(wpa_ie) - - wpa_ie_len); - if (len > 0) - wpa_ie_len += len; - } + wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq, + wpa_ie + wpa_ie_len, + max_wpa_ie_len - + wpa_ie_len); } -#endif /* CONFIG_MBO */ /* * Workaround: Add Extended Capabilities element only if the AP @@ -2333,7 +2743,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) int ext_capab_len; ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, sizeof(ext_capab)); - if (ext_capab_len > 0) { + if (ext_capab_len > 0 && + wpa_ie_len + ext_capab_len <= max_wpa_ie_len) { u8 *pos = wpa_ie; if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN) pos += 2 + pos[1]; @@ -2348,13 +2759,15 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if (is_hs20_network(wpa_s, ssid, bss)) { struct wpabuf *hs20; - hs20 = wpabuf_alloc(20); + hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN); if (hs20) { int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid); size_t len; - wpas_hs20_add_indication(hs20, pps_mo_id); - len = sizeof(wpa_ie) - wpa_ie_len; + wpas_hs20_add_indication(hs20, pps_mo_id, + get_hs20_version(bss)); + wpas_hs20_add_roam_cons_sel(hs20, ssid); + len = max_wpa_ie_len - wpa_ie_len; if (wpabuf_len(hs20) <= len) { os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20), wpabuf_len(hs20)); @@ -2371,7 +2784,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]; size_t len; - len = sizeof(wpa_ie) - wpa_ie_len; + len = max_wpa_ie_len - wpa_ie_len; if (wpabuf_len(buf) <= len) { os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(buf), wpabuf_len(buf)); @@ -2383,7 +2796,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if (wpa_s->fst_ies) { int fst_ies_len = wpabuf_len(wpa_s->fst_ies); - if (wpa_ie_len + fst_ies_len <= sizeof(wpa_ie)) { + if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) { os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(wpa_s->fst_ies), fst_ies_len); wpa_ie_len += fst_ies_len; @@ -2392,20 +2805,314 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) #endif /* CONFIG_FST */ #ifdef CONFIG_MBO - if (mbo) { + mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL; + if (mbo_ie) { int len; len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len, - sizeof(wpa_ie) - wpa_ie_len); + max_wpa_ie_len - wpa_ie_len, + !!mbo_attr_from_mbo_ie(mbo_ie, + OCE_ATTR_ID_CAPA_IND)); if (len >= 0) wpa_ie_len += len; } #endif /* CONFIG_MBO */ +#ifdef CONFIG_FILS + if (algs == WPA_AUTH_ALG_FILS) { + size_t len; + + len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len, + max_wpa_ie_len - wpa_ie_len); + wpa_ie_len += len; + } +#endif /* CONFIG_FILS */ + +#ifdef CONFIG_OWE +#ifdef CONFIG_TESTING_OPTIONS + if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) { + wpa_printf(MSG_INFO, "TESTING: Override OWE DH element"); + } else +#endif /* CONFIG_TESTING_OPTIONS */ + if (algs == WPA_AUTH_ALG_OPEN && + ssid->key_mgmt == WPA_KEY_MGMT_OWE) { + struct wpabuf *owe_ie; + u16 group; + + if (ssid->owe_group) { + group = ssid->owe_group; + } else if (wpa_s->assoc_status_code == + WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { + if (wpa_s->last_owe_group == 19) + group = 20; + else if (wpa_s->last_owe_group == 20) + group = 21; + else + group = OWE_DH_GROUP; + } else { + group = OWE_DH_GROUP; + } + + wpa_s->last_owe_group = group; + wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group); + owe_ie = owe_build_assoc_req(wpa_s->wpa, group); + if (owe_ie && + wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) { + os_memcpy(wpa_ie + wpa_ie_len, + wpabuf_head(owe_ie), wpabuf_len(owe_ie)); + wpa_ie_len += wpabuf_len(owe_ie); + } + wpabuf_free(owe_ie); + } +#endif /* CONFIG_OWE */ + +#ifdef CONFIG_DPP2 + if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP && + ssid->dpp_netaccesskey) { + dpp_pfs_free(wpa_s->dpp_pfs); + wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey, + ssid->dpp_netaccesskey_len); + if (!wpa_s->dpp_pfs) { + wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS"); + /* Try to continue without PFS */ + goto pfs_fail; + } + if (wpabuf_len(wpa_s->dpp_pfs->ie) <= + max_wpa_ie_len - wpa_ie_len) { + os_memcpy(wpa_ie + wpa_ie_len, + wpabuf_head(wpa_s->dpp_pfs->ie), + wpabuf_len(wpa_s->dpp_pfs->ie)); + wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie); + } + } +pfs_fail: +#endif /* CONFIG_DPP2 */ + +#ifdef CONFIG_IEEE80211R + /* + * Add MDIE under these conditions: the network profile allows FT, + * the AP supports FT, and the mobility domain ID matches. + */ + if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) { + const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); + + if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) { + size_t len = 0; + const u8 *md = mdie + 2; + const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa); + + if (os_memcmp(md, wpa_md, + MOBILITY_DOMAIN_ID_LEN) == 0) { + /* Add mobility domain IE */ + len = wpa_ft_add_mdie( + wpa_s->wpa, wpa_ie + wpa_ie_len, + max_wpa_ie_len - wpa_ie_len, mdie); + wpa_ie_len += len; + } +#ifdef CONFIG_SME + if (len > 0 && wpa_s->sme.ft_used && + wpa_sm_has_ptk(wpa_s->wpa)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Trying to use FT over-the-air"); + algs |= WPA_AUTH_ALG_FT; + } +#endif /* CONFIG_SME */ + } + } +#endif /* CONFIG_IEEE80211R */ + + if (ssid->multi_ap_backhaul_sta) { + size_t multi_ap_ie_len; + + multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len, + max_wpa_ie_len - wpa_ie_len, + MULTI_AP_BACKHAUL_STA); + if (multi_ap_ie_len == 0) { + wpa_printf(MSG_ERROR, + "Multi-AP: Failed to build Multi-AP IE"); + os_free(wpa_ie); + return NULL; + } + wpa_ie_len += multi_ap_ie_len; + } + + params->wpa_ie = wpa_ie; + params->wpa_ie_len = wpa_ie_len; + params->auth_alg = algs; + if (mask) + *mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE; + + return wpa_ie; +} + + +#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) +static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s) +{ + struct wpa_driver_associate_params params; + enum wpa_drv_update_connect_params_mask mask = 0; + u8 *wpa_ie; + + if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN) + return; /* nothing to do */ + + os_memset(¶ms, 0, sizeof(params)); + wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss, + wpa_s->current_ssid, ¶ms, &mask); + if (!wpa_ie) + return; + + if (params.auth_alg != WPA_AUTH_ALG_FILS) { + os_free(wpa_ie); + return; + } + + wpa_s->auth_alg = params.auth_alg; + wpa_drv_update_connect_params(wpa_s, ¶ms, mask); + os_free(wpa_ie); +} +#endif /* CONFIG_FILS && IEEE8021X_EAPOL */ + + +#ifdef CONFIG_MBO +void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s) +{ + struct wpa_driver_associate_params params; + u8 *wpa_ie; + + /* + * Update MBO connect params only in case of change of MBO attributes + * when connected, if the AP support MBO. + */ + + if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid || + !wpa_s->current_bss || + !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) + return; + + os_memset(¶ms, 0, sizeof(params)); + wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss, + wpa_s->current_ssid, ¶ms, NULL); + if (!wpa_ie) + return; + + wpa_drv_update_connect_params(wpa_s, ¶ms, WPA_DRV_UPDATE_ASSOC_IES); + os_free(wpa_ie); +} +#endif /* CONFIG_MBO */ + + +static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_connect_work *cwork = work->ctx; + struct wpa_bss *bss = cwork->bss; + struct wpa_ssid *ssid = cwork->ssid; + struct wpa_supplicant *wpa_s = work->wpa_s; + u8 *wpa_ie; + int use_crypt, ret, i, bssid_changed; + unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt; + struct wpa_driver_associate_params params; + int wep_keys_set = 0; + int assoc_failed = 0; + struct wpa_ssid *old_ssid; + u8 prev_bssid[ETH_ALEN]; +#ifdef CONFIG_HT_OVERRIDES + struct ieee80211_ht_capabilities htcaps; + struct ieee80211_ht_capabilities htcaps_mask; +#endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + struct ieee80211_vht_capabilities vhtcaps; + struct ieee80211_vht_capabilities vhtcaps_mask; +#endif /* CONFIG_VHT_OVERRIDES */ + + if (deinit) { + if (work->started) { + wpa_s->connect_work = NULL; + + /* cancel possible auth. timeout */ + eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, + NULL); + } + wpas_connect_work_free(cwork); + return; + } + + wpa_s->connect_work = work; + + if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) || + wpas_network_disabled(wpa_s, ssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt"); + wpas_connect_work_done(wpa_s); + return; + } + + os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN); + os_memset(¶ms, 0, sizeof(params)); + wpa_s->reassociate = 0; + wpa_s->eap_expected_failure = 0; + if (bss && + (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) { +#ifdef CONFIG_IEEE80211R + const u8 *ie, *md = NULL; +#endif /* CONFIG_IEEE80211R */ + wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR + " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq); + 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); +#ifdef CONFIG_IEEE80211R + ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); + if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) + md = ie + 2; + wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0); + if (md) { + /* Prepare for the next transition */ + wpa_ft_prepare_auth_request(wpa_s->wpa, ie); + } +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_WPS + } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) && + wpa_s->conf->ap_scan == 2 && + (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { + /* Use ap_scan==1 style network selection to find the network + */ + wpas_connect_work_done(wpa_s); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return; +#endif /* CONFIG_WPS */ + } else { + wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + if (bss) + os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); + else + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + } + if (!wpa_s->pno) + wpa_supplicant_cancel_sched_scan(wpa_s); + + wpa_supplicant_cancel_scan(wpa_s); + + /* 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_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, ¶ms, NULL); + if (!wpa_ie) { + wpas_connect_work_done(wpa_s); + return; + } + wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); use_crypt = 1; cipher_pairwise = wpa_s->pairwise_cipher; cipher_group = wpa_s->group_cipher; + cipher_group_mgmt = wpa_s->mgmt_group_cipher; if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) @@ -2443,12 +3150,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if (bss) { params.ssid = bss->ssid; params.ssid_len = bss->ssid_len; - if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) { + if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set || + wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) { wpa_printf(MSG_DEBUG, "Limit connection to BSSID " MACSTR " freq=%u MHz based on scan results " - "(bssid_set=%d)", + "(bssid_set=%d wps=%d)", MAC2STR(bss->bssid), bss->freq, - ssid->bssid_set); + ssid->bssid_set, + wpa_s->key_mgmt == WPA_KEY_MGMT_WPS); params.bssid = bss->bssid; params.freq.freq = bss->freq; } @@ -2456,6 +3165,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.freq_hint = bss->freq; params.pbss = bss_is_pbss(bss); } else { + if (ssid->bssid_hint_set) + params.bssid_hint = ssid->bssid_hint; + params.ssid = ssid->ssid; params.ssid_len = ssid->ssid_len; params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0; @@ -2480,13 +3192,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.beacon_int = wpa_s->conf->beacon_int; } - params.wpa_ie = wpa_ie; - params.wpa_ie_len = wpa_ie_len; params.pairwise_suite = cipher_pairwise; params.group_suite = cipher_group; + params.mgmt_group_suite = cipher_group_mgmt; params.key_mgmt_suite = wpa_s->key_mgmt; params.wpa_proto = wpa_s->wpa_proto; - params.auth_alg = algs; + 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++) { @@ -2496,7 +3207,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } params.wep_tx_keyidx = ssid->wep_tx_keyidx; - if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) && (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { params.passphrase = ssid->passphrase; @@ -2504,6 +3215,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.psk = ssid->psk; } + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) && + (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B || + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) + params.req_key_mgmt_offload = 1; + if (wpa_s->conf->key_mgmt_offload) { if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || @@ -2536,6 +3254,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) "MFP: require MFP"); params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_REQUIRED; +#ifdef CONFIG_OWE + } else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) && + !ssid->owe_only) { + params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION; +#endif /* CONFIG_OWE */ } } #endif /* CONFIG_IEEE80211W */ @@ -2578,6 +3301,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if (wpas_p2p_handle_frequency_conflicts( wpa_s, params.freq.freq, ssid) < 0) { wpas_connect_work_done(wpa_s); + os_free(wpa_ie); return; } } @@ -2589,6 +3313,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.prev_bssid = prev_bssid; ret = wpa_drv_associate(wpa_s, ¶ms); + os_free(wpa_ie); if (ret < 0) { wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " "failed"); @@ -2724,14 +3449,22 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, zero_addr = 1; } + if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0) + wpa_s->enabled_4addr_mode = 0; + #ifdef CONFIG_TDLS wpa_tdls_teardown_peers(wpa_s->wpa); #endif /* CONFIG_TDLS */ #ifdef CONFIG_MESH if (wpa_s->ifmsh) { + struct mesh_conf *mconf; + + mconf = wpa_s->ifmsh->mconf; wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s", wpa_s->ifname); + wpas_notify_mesh_group_removed(wpa_s, mconf->meshid, + mconf->meshid_len, reason_code); wpa_supplicant_leave_mesh(wpa_s); } #endif /* CONFIG_MESH */ @@ -2756,6 +3489,7 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, return; ssid->disabled = 0; + ssid->owe_transition_bss_select_count = 0; wpas_clear_temp_disabled(wpa_s, ssid, 1); wpas_notify_network_enabled_changed(wpa_s, ssid); @@ -2921,13 +3655,19 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, wpas_notify_network_enabled_changed( wpa_s, other_ssid); } - if (wpa_s->current_ssid) + if (wpa_s->current_ssid) { + if (wpa_s->wpa_state >= WPA_AUTHENTICATING) + wpa_s->own_disconnect_req = 1; wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } } else if (ssid->disabled != 2) { - if (ssid == wpa_s->current_ssid) + if (ssid == wpa_s->current_ssid) { + if (wpa_s->wpa_state >= WPA_AUTHENTICATING) + wpa_s->own_disconnect_req = 1; wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } was_disabled = ssid->disabled; @@ -3013,6 +3753,9 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpa_s->disconnected = 0; wpa_s->reassociate = 1; + wpa_s->last_owe_group = 0; + if (ssid) + ssid->owe_transition_bss_select_count = 0; if (wpa_s->connect_without_scan || wpa_supplicant_fast_associate(wpa_s) != 1) { @@ -3230,6 +3973,41 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level, } +#ifdef CONFIG_OWE +static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid, + const u8 *entry_ssid, size_t entry_ssid_len) +{ + const u8 *owe, *pos, *end; + u8 ssid_len; + struct wpa_bss *bss; + + /* Check network profile SSID aganst the SSID in the + * OWE Transition Mode element. */ + + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (!bss) + return 0; + + owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); + if (!owe) + return 0; + + pos = owe + 6; + end = owe + 2 + owe[1]; + + if (end - pos < ETH_ALEN + 1) + return 0; + pos += ETH_ALEN; + ssid_len = *pos++; + if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN) + return 0; + + return entry_ssid_len == ssid_len && + os_memcmp(pos, entry_ssid, ssid_len) == 0; +} +#endif /* CONFIG_OWE */ + + /** * wpa_supplicant_get_ssid - Get a pointer to the current network structure * @wpa_s: Pointer to wpa_supplicant data @@ -3265,7 +4043,9 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s) while (entry) { if (!wpas_network_disabled(wpa_s, entry) && ((ssid_len == entry->ssid_len && - os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) && + (!entry->ssid || + os_memcmp(ssid, entry->ssid, ssid_len) == 0)) || + wired) && (!entry->bssid_set || os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) return entry; @@ -3278,6 +4058,15 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s) return entry; #endif /* CONFIG_WPS */ +#ifdef CONFIG_OWE + if (!wpas_network_disabled(wpa_s, entry) && + owe_trans_ssid_match(wpa_s, bssid, entry->ssid, + entry->ssid_len) && + (!entry->bssid_set || + os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) + return entry; +#endif /* CONFIG_OWE */ + if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set && entry->ssid_len == 0 && os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0) @@ -3385,16 +4174,6 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, } #endif /* CONFIG_TESTING_OPTIONS */ -#ifdef CONFIG_PEERKEY - if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid && - wpa_s->current_ssid->peerkey && - !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && - wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) { - wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key"); - return; - } -#endif /* CONFIG_PEERKEY */ - if (wpa_s->wpa_state < WPA_ASSOCIATED || (wpa_s->last_eapol_matches_bssid && #ifdef CONFIG_AP @@ -3444,7 +4223,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, } if (wpa_s->eapol_received == 0 && - (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) || + (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) || !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || wpa_s->wpa_state != WPA_COMPLETED) && (wpa_s->current_ssid == NULL || @@ -3505,10 +4284,12 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN); 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_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0) return; wpa_drv_poll(wpa_s); - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len); else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { /* @@ -3534,6 +4315,11 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s) wpa_supplicant_rx_eapol, wpa_s, 0); if (wpa_s->l2 == NULL) return -1; + + if (l2_packet_set_packet_filter(wpa_s->l2, + L2_PACKET_FILTER_PKTTYPE)) + wpa_dbg(wpa_s, MSG_DEBUG, + "Failed to attach pkt_type filter"); } else { const u8 *addr = wpa_drv_get_mac_addr(wpa_s); if (addr) @@ -3673,6 +4459,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) wpa_s->sched_scanning = 0; dl_list_init(&wpa_s->bss_tmp_disallowed); + dl_list_init(&wpa_s->fils_hlp_req); return wpa_s; } @@ -3700,8 +4487,11 @@ static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs); for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { + long v; + errno = 0; - long v = strtol(tmp, &end, 16); + v = strtol(tmp, &end, 16); + if (errno == 0) { wpa_msg(wpa_s, MSG_DEBUG, "htcap value[%i]: %ld end: %p tmp: %p", @@ -3741,11 +4531,11 @@ static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s, { le16 msk; - wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled); - if (disabled == -1) return 0; + wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled); + msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE); htcaps_mask->ht_capabilities_info |= msk; if (disabled) @@ -3762,11 +4552,11 @@ static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps_mask, int factor) { - wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor); - if (factor == -1) return 0; + wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor); + if (factor < 0 || factor > 3) { wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. " "Must be 0-3 or -1", factor); @@ -3786,11 +4576,11 @@ static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps_mask, int density) { - wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density); - if (density == -1) return 0; + wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density); + if (density < 0 || density > 7) { wpa_msg(wpa_s, MSG_ERROR, "ampdu_density: %d out of range. Must be 0-7 or -1.", @@ -3811,18 +4601,11 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps_mask, int disabled) { - /* Masking these out disables HT40 */ - le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET | - HT_CAP_INFO_SHORT_GI40MHZ); - - wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled); - if (disabled) - htcaps->ht_capabilities_info &= ~msk; - else - htcaps->ht_capabilities_info |= msk; + wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled); - htcaps_mask->ht_capabilities_info |= msk; + set_disable_ht40(htcaps, disabled); + set_disable_ht40(htcaps_mask, 0); return 0; } @@ -3837,7 +4620,8 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s, le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ | HT_CAP_INFO_SHORT_GI40MHZ); - wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled); + if (disabled) + wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled); if (disabled) htcaps->ht_capabilities_info &= ~msk; @@ -3858,7 +4642,8 @@ static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s, /* Masking these out disables LDPC */ le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP); - wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled); + if (disabled) + wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled); if (disabled) htcaps->ht_capabilities_info &= ~msk; @@ -3871,6 +4656,58 @@ static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s, } +static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s, + struct ieee80211_ht_capabilities *htcaps, + struct ieee80211_ht_capabilities *htcaps_mask, + int tx_stbc) +{ + le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC); + + if (tx_stbc == -1) + return 0; + + wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc); + + if (tx_stbc < 0 || tx_stbc > 1) { + wpa_msg(wpa_s, MSG_ERROR, + "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc); + return -EINVAL; + } + + htcaps_mask->ht_capabilities_info |= msk; + htcaps->ht_capabilities_info &= ~msk; + htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk; + + return 0; +} + + +static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s, + struct ieee80211_ht_capabilities *htcaps, + struct ieee80211_ht_capabilities *htcaps_mask, + int rx_stbc) +{ + le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK); + + if (rx_stbc == -1) + return 0; + + wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc); + + if (rx_stbc < 0 || rx_stbc > 3) { + wpa_msg(wpa_s, MSG_ERROR, + "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc); + return -EINVAL; + } + + htcaps_mask->ht_capabilities_info |= msk; + htcaps->ht_capabilities_info &= ~msk; + htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk; + + return 0; +} + + void wpa_supplicant_apply_ht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params) @@ -3895,6 +4732,8 @@ void wpa_supplicant_apply_ht_overrides( wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40); wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi); wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc); + wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc); + wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc); if (ssid->ht40_intolerant) { le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT); @@ -3929,6 +4768,16 @@ void wpa_supplicant_apply_vht_overrides( vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask); #ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_sgi) { + vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 | + VHT_CAP_SHORT_GI_160); + vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 | + VHT_CAP_SHORT_GI_160); + wpa_msg(wpa_s, MSG_DEBUG, + "disable-sgi override specified, vht-caps: 0x%x", + vhtcaps->vht_capabilities_info); + } + /* if max ampdu is <= 3, we have to make the HT cap the same */ if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) { int max_ampdu; @@ -4098,10 +4947,14 @@ static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data) { struct wpa_supplicant *wpa_s = ctx; - WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0); + if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) { + wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR, + __func__, MAC2STR(wpa_s->bssid), MAC2STR(da)); + return -1; + } return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, - wpa_s->own_addr, wpa_s->bssid, - wpabuf_head(data), wpabuf_len(data), + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(data), wpabuf_len(data), 0); } @@ -4289,7 +5142,7 @@ static void radio_work_free(struct wpa_radio_work *work) if (work->started) { work->wpa_s->radio->num_active_works--; wpa_dbg(work->wpa_s, MSG_DEBUG, - "radio_work_free('%s'@%p: num_active_works --> %u", + "radio_work_free('%s'@%p): num_active_works --> %u", work->type, work, work->wpa_s->radio->num_active_works); } @@ -4299,6 +5152,20 @@ static void radio_work_free(struct wpa_radio_work *work) } +static int radio_work_is_connect(struct wpa_radio_work *work) +{ + return os_strcmp(work->type, "sme-connect") == 0 || + os_strcmp(work->type, "connect") == 0; +} + + +static int radio_work_is_scan(struct wpa_radio_work *work) +{ + return os_strcmp(work->type, "scan") == 0 || + os_strcmp(work->type, "p2p-scan") == 0; +} + + static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio) { struct wpa_radio_work *active_work = NULL; @@ -4328,8 +5195,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio) return NULL; } - if (os_strcmp(active_work->type, "sme-connect") == 0 || - os_strcmp(active_work->type, "connect") == 0) { + if (radio_work_is_connect(active_work)) { /* * If the active work is either connect or sme-connect, * do not parallelize them with other radio works. @@ -4348,10 +5214,20 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio) * If connect or sme-connect are enqueued, parallelize only * those operations ahead of them in the queue. */ - if (os_strcmp(tmp->type, "connect") == 0 || - os_strcmp(tmp->type, "sme-connect") == 0) + if (radio_work_is_connect(tmp)) break; + /* Serialize parallel scan and p2p_scan operations on the same + * interface since the driver_nl80211 mechanism for tracking + * scan cookies does not yet have support for this. */ + if (active_work->wpa_s == tmp->wpa_s && + radio_work_is_scan(active_work) && + radio_work_is_scan(tmp)) { + wpa_dbg(active_work->wpa_s, MSG_DEBUG, + "Do not start work '%s' when another work '%s' is already scheduled", + tmp->type, active_work->type); + continue; + } /* * Check that the radio works are distinct and * on different bands. @@ -4473,6 +5349,22 @@ void radio_remove_works(struct wpa_supplicant *wpa_s, } +void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx) +{ + struct wpa_radio_work *work; + struct wpa_radio *radio = wpa_s->radio; + + dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) { + if (work->ctx != ctx) + continue; + wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s", + work->type, work, work->started ? " (started)" : ""); + radio_work_free(work); + break; + } +} + + static void radio_remove_interface(struct wpa_supplicant *wpa_s) { struct wpa_radio *radio = wpa_s->radio; @@ -4625,7 +5517,7 @@ radio_work_pending(struct wpa_supplicant *wpa_s, const char *type) static int wpas_init_driver(struct wpa_supplicant *wpa_s, - struct wpa_interface *iface) + const struct wpa_interface *iface) { const char *ifname, *driver, *rn; @@ -4673,11 +5565,47 @@ next_driver: } +#ifdef CONFIG_GAS_SERVER + +static void wpas_gas_server_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) +{ + wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR + " result=%s", + freq, MAC2STR(dst), + result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : + (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : + "FAILED")); + gas_server_tx_status(wpa_s->gas_server, dst, data, data_len, + result == OFFCHANNEL_SEND_ACTION_SUCCESS); +} + + +static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da, + struct wpabuf *buf, unsigned int wait_time) +{ + struct wpa_supplicant *wpa_s = ctx; + const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + if (wait_time > wpa_s->max_remain_on_chan) + wait_time = wpa_s->max_remain_on_chan; + + offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast, + wpabuf_head(buf), wpabuf_len(buf), + wait_time, wpas_gas_server_tx_status, 0); +} + +#endif /* CONFIG_GAS_SERVER */ + static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, - struct wpa_interface *iface) + const struct wpa_interface *iface) { struct wpa_driver_capa capa; int capa_res; + u8 dfs_domain; wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver " "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname, @@ -4707,7 +5635,13 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, return -1; } wpa_s->confanother = os_rel2abs_path(iface->confanother); - wpa_config_read(wpa_s->confanother, wpa_s->conf); + if (wpa_s->confanother && + !wpa_config_read(wpa_s->confanother, wpa_s->conf)) { + wpa_printf(MSG_ERROR, + "Failed to read or parse configuration '%s'.", + wpa_s->confanother); + return -1; + } /* * Override ctrl_interface and driver_param if set on command @@ -4805,7 +5739,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s, &wpa_s->hw.num_modes, - &wpa_s->hw.flags); + &wpa_s->hw.flags, + &dfs_domain); if (wpa_s->hw.modes) { u16 i; @@ -4856,6 +5791,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, capa.mac_addr_rand_sched_scan_supported) wpa_s->mac_addr_rand_supported |= (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO); + + wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); + if (wpa_s->extended_capa && + wpa_s->extended_capa_len >= 3 && + wpa_s->extended_capa[2] & 0x40) + wpa_s->multi_bss_support = 1; } if (wpa_s->max_remain_on_chan == 0) wpa_s->max_remain_on_chan = 1000; @@ -4867,8 +5808,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, */ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) wpa_s->p2p_mgmt = iface->p2p_mgmt; - else - iface->p2p_mgmt = 1; if (wpa_s->num_multichan_concurrent == 0) wpa_s->num_multichan_concurrent = 1; @@ -4877,10 +5816,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, return -1; #ifdef CONFIG_TDLS - if ((!iface->p2p_mgmt || - !(wpa_s->drv_flags & - WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) && - wpa_tdls_init(wpa_s->wpa)) + if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa)) return -1; #endif /* CONFIG_TDLS */ @@ -4915,6 +5851,19 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, if (wpas_wps_init(wpa_s)) return -1; +#ifdef CONFIG_GAS_SERVER + wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx); + if (!wpa_s->gas_server) { + wpa_printf(MSG_ERROR, "Failed to initialize GAS server"); + return -1; + } +#endif /* CONFIG_GAS_SERVER */ + +#ifdef CONFIG_DPP + if (wpas_dpp_init(wpa_s) < 0) + return -1; +#endif /* CONFIG_DPP */ + if (wpa_supplicant_init_eapol(wpa_s) < 0) return -1; wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); @@ -4939,7 +5888,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, return -1; } - if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) { + if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) || + wpa_s->p2p_mgmt) && + wpas_p2p_init(wpa_s->global, wpa_s) < 0) { wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P"); return -1; } @@ -4947,6 +5898,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, if (wpa_bss_init(wpa_s) < 0) return -1; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + dl_list_init(&wpa_s->mesh_external_pmksa_cache); +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + /* * Set Wake-on-WLAN triggers, if configured. * Note: We don't restore/remove the triggers on shutdown (it doesn't @@ -4958,8 +5915,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, #ifdef CONFIG_EAP_PROXY { size_t len; - wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi, - &len); + wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1, + wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { wpa_s->imsi[len] = '\0'; wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)", @@ -4984,6 +5941,17 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, hs20_init(wpa_s); #endif /* CONFIG_HS20 */ #ifdef CONFIG_MBO + if (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; + if ((wpa_s->conf->oce & OCE_STA_CFON) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) { + /* TODO: Need to add STA-CFON support */ + wpa_printf(MSG_ERROR, + "OCE STA-CFON feature is not yet supported"); + } + } wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan); #endif /* CONFIG_MBO */ @@ -5248,6 +6216,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global, #ifdef CONFIG_MESH unsigned int mesh_if_created = wpa_s->mesh_if_created; char *ifname = NULL; + struct wpa_supplicant *parent = wpa_s->parent; #endif /* CONFIG_MESH */ /* Remove interface from the global list of interfaces */ @@ -5283,7 +6252,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global, #ifdef CONFIG_MESH if (mesh_if_created) { - wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname); + wpa_drv_if_remove(parent, WPA_IF_MESH, ifname); os_free(ifname); } #endif /* CONFIG_MESH */ @@ -5647,6 +6616,16 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s) if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS) wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans); + if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) { + struct wpa_driver_capa capa; + int res = wpa_drv_get_capa(wpa_s, &capa); + + if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0) + wpa_printf(MSG_ERROR, + "Failed to update wowlan_triggers to '%s'", + wpa_s->conf->wowlan_triggers); + } + #ifdef CONFIG_WPS wpas_wps_update_config(wpa_s); #endif /* CONFIG_WPS */ @@ -5801,11 +6780,43 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) * TODO: if more than one possible AP is available in scan results, * could try the other ones before requesting a new scan. */ + + /* speed up the connection attempt with normal scan */ + wpa_s->normal_scans = 0; wpa_supplicant_req_scan(wpa_s, timeout / 1000, 1000 * (timeout % 1000)); } +#ifdef CONFIG_FILS +void fils_connection_failure(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + const u8 *realm, *username, *rrk; + size_t realm_len, username_len, rrk_len; + u16 next_seq_num; + + if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) || + eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, + &username, &username_len, + &realm, &realm_len, &next_seq_num, + &rrk, &rrk_len) != 0 || + !realm) + return; + + wpa_hexdump_ascii(MSG_DEBUG, + "FILS: Store last connection failure realm", + realm, realm_len); + os_free(wpa_s->last_con_fail_realm); + wpa_s->last_con_fail_realm = os_malloc(realm_len); + if (wpa_s->last_con_fail_realm) { + wpa_s->last_con_fail_realm_len = realm_len; + os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len); + } +} +#endif /* CONFIG_FILS */ + + int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s) { return wpa_s->conf->ap_scan == 2 || @@ -5876,6 +6887,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_SIM: str_clear_free(eap->external_sim_resp); eap->external_sim_resp = os_strdup(value); + eap->pending_req_sim = 0; break; case WPA_CTRL_REQ_PSK_PASSPHRASE: if (wpa_config_set(ssid, "psk", value, 0) < 0) @@ -5944,6 +6956,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk && + !(wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password) && !ssid->mem_only_psk) return 1; @@ -6128,6 +7141,7 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s) wpa_s->extra_blacklist_count = 0; wpa_s->disconnected = 0; wpa_s->reassociate = 1; + wpa_s->last_owe_group = 0; if (wpa_supplicant_fast_associate(wpa_s) != 1) wpa_supplicant_req_scan(wpa_s, 0, 0); @@ -6154,6 +7168,8 @@ void wpas_request_disconnection(struct wpa_supplicant *wpa_s) wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); + radio_remove_works(wpa_s, "connect", 0); + radio_remove_works(wpa_s, "sme-connect", 0); } @@ -6254,489 +7270,6 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, } -static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx) -{ - struct rrm_data *rrm = data; - - if (!rrm->notify_neighbor_rep) { - wpa_printf(MSG_ERROR, - "RRM: Unexpected neighbor report timeout"); - return; - } - - wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE"); - rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL); - - rrm->notify_neighbor_rep = NULL; - rrm->neighbor_rep_cb_ctx = NULL; -} - - -/* - * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant - * @wpa_s: Pointer to wpa_supplicant - */ -void wpas_rrm_reset(struct wpa_supplicant *wpa_s) -{ - wpa_s->rrm.rrm_used = 0; - - eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, - NULL); - if (wpa_s->rrm.notify_neighbor_rep) - wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); - wpa_s->rrm.next_neighbor_rep_token = 1; -} - - -/* - * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report - * @wpa_s: Pointer to wpa_supplicant - * @report: Neighbor report buffer, prefixed by a 1-byte dialog token - * @report_len: Length of neighbor report buffer - */ -void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, - const u8 *report, size_t report_len) -{ - struct wpabuf *neighbor_rep; - - wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len); - if (report_len < 1) - return; - - if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) { - wpa_printf(MSG_DEBUG, - "RRM: Discarding neighbor report with token %d (expected %d)", - report[0], wpa_s->rrm.next_neighbor_rep_token - 1); - return; - } - - eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, - NULL); - - if (!wpa_s->rrm.notify_neighbor_rep) { - wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report"); - return; - } - - /* skipping the first byte, which is only an id (dialog token) */ - neighbor_rep = wpabuf_alloc(report_len - 1); - if (neighbor_rep == NULL) - return; - wpabuf_put_data(neighbor_rep, report + 1, report_len - 1); - wpa_printf(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; - wpa_s->rrm.neighbor_rep_cb_ctx = NULL; -} - - -#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) -/* Workaround different, undefined for Windows, error codes used here */ -#define ENOTCONN -1 -#define EOPNOTSUPP -1 -#define ECANCELED -1 -#endif - -/* Measurement Request element + Location Subject + Maximum Age subelement */ -#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4) -/* Measurement Request element + Location Civic Request */ -#define MEASURE_REQUEST_CIVIC_LEN (3 + 5) - - -/** - * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP - * @wpa_s: Pointer to wpa_supplicant - * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE - * is sent in the request. - * @lci: if set, neighbor request will include LCI request - * @civic: if set, neighbor request will include civic location request - * @cb: Callback function to be called once the requested report arrives, or - * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds. - * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's - * the requester's responsibility to free it. - * In the latter case NULL will be sent in 'neighbor_rep'. - * @cb_ctx: Context value to send the callback function - * Returns: 0 in case of success, negative error code otherwise - * - * In case there is a previous request which has not been answered yet, the - * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT. - * Request must contain a callback function. - */ -int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, - const struct wpa_ssid_value *ssid, - int lci, int civic, - void (*cb)(void *ctx, - struct wpabuf *neighbor_rep), - void *cb_ctx) -{ - struct wpabuf *buf; - 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."); - return -ENOTCONN; - } - - if (!wpa_s->rrm.rrm_used) { - wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection."); - return -EOPNOTSUPP; - } - - rrm_ie = wpa_bss_get_ie(wpa_s->current_bss, - 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."); - return -EOPNOTSUPP; - } - - if (!cb) { - wpa_printf(MSG_DEBUG, - "RRM: Neighbor Report request must provide a callback."); - return -EINVAL; - } - - /* Refuse if there's a live request */ - if (wpa_s->rrm.notify_neighbor_rep) { - wpa_printf(MSG_DEBUG, - "RRM: Currently handling previous Neighbor Report."); - return -EBUSY; - } - - /* 3 = action category + action code + dialog token */ - buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) + - (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"); - 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); - - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST); - wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token); - if (ssid) { - wpabuf_put_u8(buf, WLAN_EID_SSID); - wpabuf_put_u8(buf, ssid->ssid_len); - wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len); - } - - if (lci) { - /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); - wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN); - - /* - * Measurement token; nonzero number that is unique among the - * Measurement Request elements in a particular frame. - */ - wpabuf_put_u8(buf, 1); /* Measurement Token */ - - /* - * Parallel, Enable, Request, and Report bits are 0, Duration is - * reserved. - */ - wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ - wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */ - - /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */ - /* Location Subject */ - wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); - - /* Optional Subelements */ - /* - * IEEE P802.11-REVmc/D5.0 Figure 9-170 - * The Maximum Age subelement is required, otherwise the AP can - * send only data that was determined after receiving the - * request. Setting it here to unlimited age. - */ - wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); - wpabuf_put_u8(buf, 2); - wpabuf_put_le16(buf, 0xffff); - } - - if (civic) { - /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); - wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN); - - /* - * Measurement token; nonzero number that is unique among the - * Measurement Request elements in a particular frame. - */ - wpabuf_put_u8(buf, 2); /* Measurement Token */ - - /* - * Parallel, Enable, Request, and Report bits are 0, Duration is - * reserved. - */ - wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ - /* Measurement Type */ - wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC); - - /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14: - * Location Civic request */ - /* Location Subject */ - wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); - wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */ - /* Location Service Interval Units: Seconds */ - wpabuf_put_u8(buf, 0); - /* Location Service Interval: 0 - Only one report is requested - */ - wpabuf_put_le16(buf, 0); - /* No optional subelements */ - } - - wpa_s->rrm.next_neighbor_rep_token++; - - 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"); - wpabuf_free(buf); - return -ECANCELED; - } - - wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx; - wpa_s->rrm.notify_neighbor_rep = cb; - eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0, - wpas_rrm_neighbor_rep_timeout_handler, - &wpa_s->rrm, NULL); - - wpabuf_free(buf); - return 0; -} - - -static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s, - const u8 *request, size_t len, - struct wpabuf *report) -{ - u8 token, type, subject; - u16 max_age = 0; - struct os_reltime t, diff; - unsigned long diff_l; - u8 *ptoken; - const u8 *subelem; - - if (!wpa_s->lci || len < 3 + 4) - return report; - - token = *request++; - /* Measurement request mode isn't used */ - request++; - type = *request++; - subject = *request++; - - wpa_printf(MSG_DEBUG, - "Measurement request token %u type %u location subject %u", - token, type, subject); - - if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) { - wpa_printf(MSG_INFO, - "Not building LCI report - bad type or location subject"); - return report; - } - - /* Subelements are formatted exactly like elements */ - subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE); - if (subelem && subelem[1] == 2) - max_age = WPA_GET_LE16(subelem + 2); - - if (os_get_reltime(&t)) - return report; - - os_reltime_sub(&t, &wpa_s->lci_time, &diff); - /* LCI age is calculated in 10th of a second units. */ - diff_l = diff.sec * 10 + diff.usec / 100000; - - if (max_age != 0xffff && max_age < diff_l) - return report; - - if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci))) - return report; - - wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT); - wpabuf_put_u8(report, wpabuf_len(wpa_s->lci)); - /* We'll override user's measurement token */ - ptoken = wpabuf_put(report, 0); - wpabuf_put_buf(report, wpa_s->lci); - *ptoken = token; - - return report; -} - - -void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, - const u8 *src, - const u8 *frame, size_t len) -{ - struct wpabuf *buf, *report; - u8 token; - const u8 *ie, *end; - - if (wpa_s->wpa_state != WPA_COMPLETED) { - wpa_printf(MSG_INFO, - "RRM: Ignoring radio measurement request: Not associated"); - return; - } - - if (!wpa_s->rrm.rrm_used) { - wpa_printf(MSG_INFO, - "RRM: Ignoring radio measurement request: Not RRM network"); - return; - } - - if (len < 3) { - wpa_printf(MSG_INFO, - "RRM: Ignoring too short radio measurement request"); - return; - } - - end = frame + len; - - token = *frame++; - - /* Ignore number of repetitions because it's not used in LCI request */ - frame += 2; - - report = NULL; - while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) && - ie[1] >= 3) { - u8 msmt_type; - - msmt_type = ie[4]; - wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type); - - switch (msmt_type) { - case MEASURE_TYPE_LCI: - report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1], - report); - break; - default: - wpa_printf(MSG_INFO, - "RRM: Unsupported radio measurement request %d", - msmt_type); - break; - } - - frame = ie + ie[1] + 2; - } - - if (!report) - return; - - buf = wpabuf_alloc(3 + wpabuf_len(report)); - if (!buf) { - wpabuf_free(report); - return; - } - - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT); - wpabuf_put_u8(buf, token); - - wpabuf_put_buf(buf, report); - wpabuf_free(report); - - if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src, - wpa_s->own_addr, wpa_s->bssid, - wpabuf_head(buf), wpabuf_len(buf), 0)) { - wpa_printf(MSG_ERROR, - "RRM: Radio measurement report failed: Sending Action frame failed"); - } - wpabuf_free(buf); -} - - -void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, - const u8 *src, - const u8 *frame, size_t len, - int rssi) -{ - struct wpabuf *buf; - const struct rrm_link_measurement_request *req; - struct rrm_link_measurement_report report; - - if (wpa_s->wpa_state != WPA_COMPLETED) { - wpa_printf(MSG_INFO, - "RRM: Ignoring link measurement request. Not associated"); - return; - } - - if (!wpa_s->rrm.rrm_used) { - wpa_printf(MSG_INFO, - "RRM: Ignoring link measurement request. Not RRM network"); - return; - } - - if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { - wpa_printf(MSG_INFO, - "RRM: Measurement report failed. TX power insertion not supported"); - return; - } - - req = (const struct rrm_link_measurement_request *) frame; - if (len < sizeof(*req)) { - wpa_printf(MSG_INFO, - "RRM: Link measurement report failed. Request too short"); - return; - } - - os_memset(&report, 0, sizeof(report)); - report.tpc.eid = WLAN_EID_TPC_REPORT; - report.tpc.len = 2; - report.rsni = 255; /* 255 indicates that RSNI is not available */ - report.dialog_token = req->dialog_token; - - /* - * It's possible to estimate RCPI based on RSSI in dBm. This - * calculation will not reflect the correct value for high rates, - * but it's good enough for Action frames which are transmitted - * with up to 24 Mbps rates. - */ - if (!rssi) - report.rcpi = 255; /* not available */ - else if (rssi < -110) - report.rcpi = 0; - else if (rssi > 0) - report.rcpi = 220; - else - report.rcpi = (rssi + 110) * 2; - - /* action_category + action_code */ - buf = wpabuf_alloc(2 + sizeof(report)); - if (buf == NULL) { - wpa_printf(MSG_ERROR, - "RRM: Link measurement report failed. Buffer allocation failed"); - return; - } - - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT); - wpabuf_put_data(buf, &report, sizeof(report)); - wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:", - wpabuf_head(buf), wpabuf_len(buf)); - - if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src, - wpa_s->own_addr, wpa_s->bssid, - wpabuf_head(buf), wpabuf_len(buf), 0)) { - wpa_printf(MSG_ERROR, - "RRM: Link measurement report failed. Send action failed"); - } - wpabuf_free(buf); -} - - struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame) { @@ -6850,19 +7383,55 @@ wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s, } +static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s) +{ + struct wpa_bss_tmp_disallowed *tmp; + unsigned int num_bssid = 0; + u8 *bssids; + int ret; + + bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN); + if (!bssids) + return -1; + dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid, + ETH_ALEN); + num_bssid++; + } + ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids); + os_free(bssids); + return ret; +} + + +static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx; + + /* Make sure the bss is not already freed */ + dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (bss == tmp) { + dl_list_del(&tmp->list); + os_free(tmp); + wpa_set_driver_tmp_disallow_list(wpa_s); + break; + } + } +} + + void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, - unsigned int sec) + unsigned int sec, int rssi_threshold) { struct wpa_bss_tmp_disallowed *bss; - struct os_reltime until; - - os_get_reltime(&until); - until.sec += sec; bss = wpas_get_disallowed_bss(wpa_s, bssid); if (bss) { - bss->disallowed_until = until; - return; + eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss); + goto finish; } bss = os_malloc(sizeof(*bss)); @@ -6872,38 +7441,35 @@ void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, return; } - bss->disallowed_until = until; os_memcpy(bss->bssid, bssid, ETH_ALEN); dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list); + wpa_set_driver_tmp_disallow_list(wpa_s); + +finish: + bss->rssi_threshold = rssi_threshold; + eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout, + wpa_s, bss); } -int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid) +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) { - struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev; - struct os_reltime now, age; - - os_get_reltime(&now); + struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev; dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed, struct wpa_bss_tmp_disallowed, list) { - if (!os_reltime_before(&now, &tmp->disallowed_until)) { - /* This BSS is not disallowed anymore */ - dl_list_del(&tmp->list); - os_free(tmp); - continue; - } - if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) { - bss = tmp; + if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) { + disallowed = tmp; break; } } - if (!bss) + if (!disallowed) + return 0; + + if (disallowed->rssi_threshold != 0 && + bss->level > disallowed->rssi_threshold) return 0; - os_reltime_sub(&bss->disallowed_until, &now, &age); - wpa_printf(MSG_DEBUG, - "BSS " MACSTR " disabled for %ld.%0ld seconds", - MAC2STR(bss->bssid), age.sec, age.usec); return 1; } diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf index b2e49d8ae325..f5c2cfcdb63c 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf @@ -87,9 +87,7 @@ eapol_version=1 # 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. -# Note: macsec_qca driver is one type of Ethernet driver which implements -# macsec feature. +# also 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, @@ -173,13 +171,13 @@ fast_reauth=1 # OpenSSL cipher string # # This is an OpenSSL specific configuration option for configuring the default -# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default. +# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW" +# by default) is used. # See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation # on cipher suite configuration. This is applicable only if wpa_supplicant is # built to use OpenSSL. #openssl_ciphers=DEFAULT:!EXP:!LOW - # Dynamic EAP methods # If EAP methods were built dynamically as shared object files, they need to be # loaded here before being used in the network blocks. By default, EAP methods @@ -208,9 +206,15 @@ fast_reauth=1 # Wi-Fi Protected Setup (WPS) parameters # Universally Unique IDentifier (UUID; see RFC 4122) of the device -# If not configured, UUID will be generated based on the local MAC address. +# If not configured, UUID will be generated based on the mechanism selected with +# the auto_uuid parameter. #uuid=12345678-9abc-def0-1234-56789abcdef0 +# Automatic UUID behavior +# 0 = generate static value based on the local MAC address (default) +# 1 = generate a random UUID every time wpa_supplicant starts +#auto_uuid=0 + # Device Name # User-friendly description of device; up to 32 octets encoded in UTF-8 #device_name=Wireless Client @@ -266,6 +270,14 @@ fast_reauth=1 # to external program(s) #wps_cred_processing=0 +# Whether to enable SAE (WPA3-Personal transition mode) automatically for +# WPA2-PSK credentials received using WPS. +# 0 = only add the explicitly listed WPA2-PSK configuration (default) +# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the +# station gets configured in WPA3-Personal transition mode (supports both +# WPA2-Personal (PSK) and WPA3-Personal (SAE) APs). +#wps_cred_add_sae=0 + # Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing # The vendor attribute contents to be added in M1 (hex string) #wps_vendor_ext_m1=000137100100020001 @@ -294,6 +306,15 @@ fast_reauth=1 # of APs when using ap_scan=1 mode. #bss_max_count=200 +# BSS expiration age in seconds. A BSS will be removed from the local cache +# if it is not in use and has not been seen for this time. Default is 180. +#bss_expiration_age=180 + +# BSS expiration after number of scans. A BSS will be removed from the local +# cache if it is not seen in this number of scans. +# Default is 2. +#bss_expiration_scan_count=2 + # Automatic scan # This is an optional set of parameters for automatic scanning # within an interface in following format: @@ -361,11 +382,16 @@ fast_reauth=1 # Enabled SAE finite cyclic groups in preference order # By default (if this parameter is not set), the mandatory group 19 (ECC group -# defined over a 256-bit prime order field) is preferred, but other groups are -# also enabled. If this parameter is set, the groups will be tried in the -# indicated order. The group values are listed in the IANA registry: +# defined over a 256-bit prime order field, NIST P-256) is preferred and groups +# 20 (NIST P-384) and 21 (NIST P-521) are also enabled. If this parameter is +# set, the groups will be tried in the indicated order. +# The group values are listed in the IANA registry: # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9 -#sae_groups=21 20 19 26 25 +# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production +# purposes due limited security (see RFC 8247). Groups that are not as strong as +# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases +# since all implementations are required to support group 19. +#sae_groups=19 20 21 # Default value for DTIM period (if not overridden in network block) #dtim_period=2 @@ -412,11 +438,50 @@ fast_reauth=1 # 2 = like 1, but maintain OUI (with local admin bit set) #preassoc_mac_addr=0 +# MAC address policy for GAS operations +# 0 = use permanent MAC address +# 1 = use random MAC address +# 2 = like 1, but maintain OUI (with local admin bit set) +#gas_rand_mac_addr=0 + +# Lifetime of GAS random MAC address in seconds (default: 60) +#gas_rand_addr_lifetime=60 + # Interworking (IEEE 802.11u) # Enable Interworking # interworking=1 +# Enable P2P GO advertisement of Interworking +# go_interworking=1 + +# P2P GO Interworking: Access Network Type +# 0 = Private network +# 1 = Private network with guest access +# 2 = Chargeable public network +# 3 = Free public network +# 4 = Personal device network +# 5 = Emergency services only network +# 14 = Test or experimental +# 15 = Wildcard +#go_access_network_type=0 + +# P2P GO Interworking: Whether the network provides connectivity to the Internet +# 0 = Unspecified +# 1 = Network provides connectivity to the Internet +#go_internet=1 + +# P2P GO Interworking: Group Venue Info (optional) +# The available values are defined in IEEE Std 802.11-2016, 9.4.1.35. +# Example values (group,type): +# 0,0 = Unspecified +# 1,7 = Convention Center +# 1,13 = Coffee Shop +# 2,0 = Unspecified Business +# 7,1 Private Residence +#go_venue_group=7 +#go_venue_type=1 + # Homogenous ESS identifier # If this is set, scans will be used to request response only from BSSes # belonging to the specified Homogeneous ESS. This is used only if interworking @@ -542,6 +607,20 @@ fast_reauth=1 # pre-configured with the credential since the NAI Realm information # may not be available or fetched. # +# required_roaming_consortium: Required Roaming Consortium OI +# If required_roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that is required to be advertised by the AP for +# the credential to be considered matching. +# +# roaming_consortiums: Roaming Consortium OI(s) memberships +# This string field contains one or more comma delimited OIs (hexdump) +# identifying the roaming consortiums of which the provider is a member. +# The list is sorted from the most preferred one to the least preferred +# one. A match between the Roaming Consortium OIs advertised by an AP and +# the OIs in this list indicates that successful authentication is +# possible. +# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI) +# # eap: Pre-configured EAP method # This optional field can be used to specify which EAP method will be # used with this credential. If not set, the EAP method is selected @@ -669,7 +748,7 @@ fast_reauth=1 # Format: # non_pref_chan=<oper_class>:<chan>:<preference>:<reason> # Example: -# non_pref_chan="81:5:10:2 81:1:0:2 81:9:0:2" +# non_pref_chan=81:5:10:2 81:1:0:2 81:9:0:2 # MBO Cellular Data Capabilities # 1 = Cellular data connection available @@ -677,6 +756,13 @@ fast_reauth=1 # 3 = Not cellular capable (default) #mbo_cell_capa=3 +# Optimized Connectivity Experience (OCE) +# oce: Enable OCE features (bitmap) +# Set BIT(0) to Enable OCE in non-AP STA mode (default; disabled if the driver +# does not indicate support for OCE in STA mode) +# Set BIT(1) to Enable OCE in STA-CFON mode +#oce=1 + # network block # # Each network (usually AP's sharing the same SSID) is configured as a separate @@ -789,6 +875,7 @@ fast_reauth=1 # proto: list of accepted protocols # WPA = WPA/IEEE 802.11i/D3.0 # RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN) +# Note that RSN is used also for WPA3. # If not set, this defaults to: WPA RSN # # key_mgmt: list of accepted authenticated key management protocols @@ -801,15 +888,23 @@ fast_reauth=1 # instead) # FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key # FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication +# FT-EAP-SHA384 = Fast BSS Transition (IEEE 802.11r) with EAP authentication +# and using SHA384 # WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms # WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms # SAE = Simultaneous authentication of equals; pre-shared key/password -based # authentication with stronger security than WPA-PSK especially when using -# not that strong password +# not that strong password; a.k.a. WPA3-Personal # FT-SAE = SAE with FT # WPA-EAP-SUITE-B = Suite B 128-bit level # WPA-EAP-SUITE-B-192 = Suite B 192-bit level # OSEN = Hotspot 2.0 Rel 2 online signup connection +# FILS-SHA256 = Fast Initial Link Setup with SHA256 +# FILS-SHA384 = Fast Initial Link Setup with SHA384 +# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256 +# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384 +# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open) +# DPP = Device Provisioning Protocol # If not set, this defaults to: WPA-PSK WPA-EAP # # ieee80211w: whether management frame protection is enabled @@ -822,6 +917,13 @@ fast_reauth=1 # PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256 # (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used) # +# ocv: whether operating channel validation is enabled +# This is a countermeasure against multi-channel man-in-the-middle attacks. +# Enabling this automatically also enables ieee80211w, if not yet enabled. +# 0 = disabled (default) +# 1 = enabled +#ocv=1 +# # auth_alg: list of allowed IEEE 802.11 authentication algorithms # OPEN = Open System authentication (required for WPA/WPA2) # SHARED = Shared Key authentication (requires static WEP keys) @@ -843,6 +945,14 @@ fast_reauth=1 # WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11] # If not set, this defaults to: CCMP TKIP WEP104 WEP40 # +# group_mgmt: list of accepted group management ciphers for RSN (PMF) +# AES-128-CMAC = BIP-CMAC-128 +# BIP-GMAC-128 +# BIP-GMAC-256 +# BIP-CMAC-256 +# If not set, no constraint on the cipher, i.e., accept whichever cipher the AP +# indicates. +# # psk: WPA preshared key; 256-bit pre-shared key # The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e., # 32 bytes or as an ASCII passphrase (in which case, the real PSK will be @@ -860,22 +970,71 @@ fast_reauth=1 # 1 = do not store psk/passphrase to the configuration file #mem_only_psk=0 # +# sae_password: SAE password +# This parameter can be used to set a password for SAE. By default, the +# passphrase from the psk parameter is used if this separate parameter is not +# used, but psk follows the WPA-PSK constraints (8..63 characters) even though +# SAE passwords do not have such constraints. +# +# sae_password_id: SAE password identifier +# This parameter can be used to set an identifier for the SAE password. By +# default, no such identifier is used. If set, the specified identifier value +# is used by the other peer to select which password to use for authentication. +# # eapol_flags: IEEE 802.1X/EAPOL options (bit field) # Dynamic WEP key required for non-WPA mode # bit0 (1): require dynamically generated unicast WEP key # bit1 (2): require dynamically generated broadcast WEP key # (3 = require both keys; default) -# Note: When using wired authentication (including macsec_qca driver), +# Note: When using wired authentication (including MACsec drivers), # eapol_flags must be set to 0 for the authentication to be completed # successfully. # # macsec_policy: IEEE 802.1X/MACsec options -# This determines how sessions are secured with MACsec. It is currently -# applicable only when using the macsec_qca driver interface. +# 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_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 wpa_supplicant can act as MACsec peers. The peer +# with lower priority will become the key server and start distributing SAKs. +# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit) +# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits) +# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string +# (2..64 hex-digits) +# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being +# default priority +# # mixed_cell: This option can be used to configure whether so called mixed # cells, i.e., networks that use both plaintext and encryption in the same # SSID, are allowed when selecting a BSS from scan results. @@ -891,18 +1050,12 @@ fast_reauth=1 # hex without quotation, e.g., 0102030405) # wep_tx_keyidx: Default WEP key index (TX) (0..3) # -# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is -# allowed. This is only used with RSN/WPA2. -# 0 = disabled (default) -# 1 = enabled -#peerkey=1 -# # 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. # # 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. +# Authenticator role in IBSS, or in AP and mesh modes. # # Following fields are only used with internal EAP implementation. # eap: space-separated list of accepted EAP methods @@ -1024,6 +1177,12 @@ fast_reauth=1 # certificate may include additional sub-level labels in addition to the # required labels. # +# More than one match string can be provided by using semicolons to +# separate the strings (e.g., example.org;example.com). When multiple +# strings are specified, a match with any one of the values is considered +# a sufficient match for the certificate, i.e., the conditions are ORed +# together. +# # For example, domain_suffix_match=example.com would match # test.example.com but would not match test-example.com. # domain_match: Constraint for server domain name @@ -1036,6 +1195,12 @@ fast_reauth=1 # no subdomains or wildcard matches are allowed. Case-insensitive # comparison is used, so "Example.com" matches "example.com", but would # not match "test.Example.com". +# +# More than one match string can be provided by using semicolons to +# separate the strings (e.g., example.org;example.com). When multiple +# strings are specified, a match with any one of the values is considered +# a sufficient match for the certificate, i.e., the conditions are ORed +# together. # phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters # (string with field-value pairs, e.g., "peapver=0" or # "peapver=1 peaplabel=1") @@ -1097,16 +1262,28 @@ fast_reauth=1 # For EAP-FAST, this must be set to 0 (or left unconfigured for the # default value to be used automatically). # tls_disable_tlsv1_0=1 - disable use of TLSv1.0 +# tls_disable_tlsv1_0=0 - explicitly enable use of TLSv1.0 (this allows +# systemwide TLS policies to be overridden) # tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers # that have issues interoperating with updated TLS version) +# tls_disable_tlsv1_1=0 - explicitly enable use of TLSv1.1 (this allows +# systemwide TLS policies to be overridden) # tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers # that have issues interoperating with updated TLS version) +# tls_disable_tlsv1_2=0 - explicitly enable use of TLSv1.2 (this allows +# systemwide TLS policies to be overridden) +# tls_disable_tlsv1_3=1 - disable use of TLSv1.3 (a workaround for AAA servers +# that have issues interoperating with updated TLS version) +# tls_disable_tlsv1_3=0 - enable TLSv1.3 (experimental - disabled by default) # tls_ext_cert_check=0 - No external server certificate validation (default) # tls_ext_cert_check=1 - External server certificate validation enabled; this # requires an external program doing validation of server certificate # chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control # interface and report the result of the validation with # CTRL-RSP_EXT_CERT_CHECK. +# tls_suiteb=0 - do not apply Suite B 192-bit constraints on TLS (default) +# tls_suiteb=1 - apply Suite B 192-bit constraints on TLS; this is used in +# particular when using Suite B with RSA keys of >= 3K (3072) bits # # Following certificate/private key fields are used in inner Phase2 # authentication when using EAP-TTLS or EAP-PEAP. @@ -1175,6 +1352,10 @@ fast_reauth=1 # update_identifier: PPS MO ID # (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) +# +# roaming_consortium_selection: Roaming Consortium Selection +# The matching Roaming Consortium OI that was used to generate this +# network profile. # Station inactivity limit # @@ -1204,6 +1385,11 @@ fast_reauth=1 # 1 = WPS disabled #wps_disabled=0 +# FILS DH Group +# 0 = PFS disabled with FILS shared key authentication (default) +# 1-65535 = DH Group to use for FILS PFS +#fils_dh_group=0 + # MAC address policy # 0 = use permanent MAC address # 1 = use random MAC address for each ESS connection @@ -1248,6 +1434,20 @@ fast_reauth=1 # Treated as hint by the kernel. # -1 = Do not make any changes. # 0-3 = Set AMPDU density (aka factor) to specified value. +# +# tx_stbc: Allow overriding STBC support for TX streams +# Value: 0-1, see IEEE Std 802.11-2016, 9.4.2.56.2. +# -1 = Do not make any changes (default) +# 0 = Set if not supported +# 1 = Set if supported +# +# rx_stbc: Allow overriding STBC support for RX streams +# Value: 0-3, see IEEE Std 802.11-2016, 9.4.2.56.2. +# -1 = Do not make any changes (default) +# 0 = Set if not supported +# 1 = Set for support of one spatial stream +# 2 = Set for support of one and two spatial streams +# 3 = Set for support of one, two and three spatial streams # disable_vht: Whether VHT should be disabled. # 0 = VHT enabled (if AP supports it) @@ -1263,6 +1463,13 @@ fast_reauth=1 # 2: MCS 0-9 # 3: not supported +# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality +# 0 = normal STA (default) +# 1 = backhaul STA +# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not +# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be +# added to a bridge to allow forwarding frames over this backhaul link. + ##### Fast Session Transfer (FST) support ##################################### # # The options in this section are only available when the build configuration @@ -1662,15 +1869,26 @@ network={ } -# Example MACsec configuration -#network={ -# key_mgmt=IEEE8021X -# eap=TTLS -# phase2="auth=PAP" -# anonymous_identity="anonymous@example.com" -# identity="user@example.com" -# password="secretr" -# ca_cert="/etc/cert/ca.pem" -# eapol_flags=0 -# macsec_policy=1 -#} +# Example configuration using EAP-TTLS for authentication and key +# generation for MACsec +network={ + key_mgmt=IEEE8021X + eap=TTLS + phase2="auth=PAP" + anonymous_identity="anonymous@example.com" + identity="user@example.com" + password="secretr" + ca_cert="/etc/cert/ca.pem" + eapol_flags=0 + macsec_policy=1 +} + +# Example configuration for MACsec with preshared key +network={ + key_mgmt=NONE + eapol_flags=0 + macsec_policy=1 + mka_cak=0123456789ABCDEF0123456789ABCDEF + mka_ckn=6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435 + mka_priority=128 +} diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h index ef9273d09a32..16e4db62aeef 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h @@ -9,6 +9,7 @@ #ifndef WPA_SUPPLICANT_I_H #define WPA_SUPPLICANT_I_H +#include "utils/bitfield.h" #include "utils/list.h" #include "common/defs.h" #include "common/sae.h" @@ -295,7 +296,7 @@ struct wpa_global { #ifdef CONFIG_WIFI_DISPLAY int wifi_display; -#define MAX_WFD_SUBELEMS 10 +#define MAX_WFD_SUBELEMS 12 struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS]; #endif /* CONFIG_WIFI_DISPLAY */ @@ -344,6 +345,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, void radio_work_done(struct wpa_radio_work *work); void radio_remove_works(struct wpa_supplicant *wpa_s, const char *type, int remove_all); +void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx); void radio_work_check_next(struct wpa_supplicant *wpa_s); struct wpa_radio_work * radio_work_pending(struct wpa_supplicant *wpa_s, const char *type); @@ -424,6 +426,12 @@ struct rrm_data { /* next_neighbor_rep_token - Next request's dialog token */ u8 next_neighbor_rep_token; + + /* token - Dialog token of the current radio measurement */ + u8 token; + + /* destination address of the current radio measurement request */ + u8 dst_addr[ETH_ALEN]; }; enum wpa_supplicant_test_failure { @@ -443,7 +451,30 @@ struct icon_entry { struct wpa_bss_tmp_disallowed { struct dl_list list; u8 bssid[ETH_ALEN]; - struct os_reltime disallowed_until; + int rssi_threshold; +}; + +struct beacon_rep_data { + u8 token; + u8 last_indication; + struct wpa_driver_scan_params scan_params; + u8 ssid[SSID_MAX_LEN]; + size_t ssid_len; + u8 bssid[ETH_ALEN]; + enum beacon_report_detail report_detail; + struct bitfield *eids; +}; + + +struct external_pmksa_cache { + struct dl_list list; + void *pmksa_cache; +}; + +struct fils_hlp_req { + struct dl_list list; + u8 dst[ETH_ALEN]; + struct wpabuf *pkt; }; /** @@ -463,15 +494,16 @@ struct wpa_supplicant { struct wpa_supplicant *next; struct l2_packet_data *l2; struct l2_packet_data *l2_br; + struct os_reltime roam_start; + struct os_reltime roam_time; + struct os_reltime session_start; + struct os_reltime session_length; unsigned char own_addr[ETH_ALEN]; unsigned char perm_addr[ETH_ALEN]; char ifname[100]; #ifdef CONFIG_MATCH_IFACE int matched; #endif /* CONFIG_MATCH_IFACE */ -#ifdef CONFIG_CTRL_IFACE_DBUS - char *dbus_path; -#endif /* CONFIG_CTRL_IFACE_DBUS */ #ifdef CONFIG_CTRL_IFACE_DBUS_NEW char *dbus_new_path; char *dbus_groupobj_path; @@ -503,6 +535,8 @@ struct wpa_supplicant { struct wpa_bss *current_bss; int ap_ies_from_associnfo; unsigned int assoc_freq; + u8 *last_con_fail_realm; + size_t last_con_fail_realm_len; /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ int pairwise_cipher; @@ -639,6 +673,7 @@ struct wpa_supplicant { struct os_reltime scan_min_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; + int *select_network_scan_freqs; int *manual_scan_freqs; int *manual_sched_scan_freqs; unsigned int manual_scan_passive:1; @@ -652,6 +687,12 @@ struct wpa_supplicant { int normal_scans; /* normal scans run before sched_scan */ int scan_for_connection; /* whether the scan request was triggered for * finding a connection */ + /* + * A unique cookie representing the vendor scan request. This cookie is + * returned from the driver interface. 0 indicates that there is no + * pending vendor scan request. + */ + u64 curr_scan_cookie; #define MAX_SCAN_ID 16 int scan_id[MAX_SCAN_ID]; unsigned int scan_id_count; @@ -705,6 +746,12 @@ struct wpa_supplicant { unsigned int mac_addr_changed:1; unsigned int added_vif:1; unsigned int wnmsleep_used:1; + unsigned int owe_transition_select:1; + unsigned int owe_transition_search:1; + unsigned int connection_set:1; + unsigned int connection_ht:1; + unsigned int connection_vht:1; + unsigned int connection_he:1; struct os_reltime last_mac_addr_change; int last_mac_addr_style; @@ -715,13 +762,15 @@ struct wpa_supplicant { int sta_uapsd; int set_ap_uapsd; int ap_uapsd; + int auth_alg; + u16 last_owe_group; #ifdef CONFIG_SME struct { u8 ssid[SSID_MAX_LEN]; size_t ssid_len; int freq; - u8 assoc_req_ie[200]; + u8 assoc_req_ie[1500]; size_t assoc_req_ie_len; int mfp; int ft_used; @@ -752,6 +801,8 @@ struct wpa_supplicant { struct wpabuf *sae_token; int sae_group_index; unsigned int sae_pmksa_caching:1; + u16 seq_num; + struct external_auth ext_auth; #endif /* CONFIG_SAE */ } sme; #endif /* CONFIG_SME */ @@ -770,6 +821,11 @@ struct wpa_supplicant { unsigned int mesh_if_created:1; unsigned int mesh_ht_enabled:1; unsigned int mesh_vht_enabled:1; + struct wpa_driver_mesh_join_params *mesh_params; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + /* struct external_pmksa_cache::list */ + struct dl_list mesh_external_pmksa_cache; +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ #endif /* CONFIG_MESH */ unsigned int off_channel_freq; @@ -789,6 +845,7 @@ struct wpa_supplicant { result); unsigned int roc_waiting_drv_freq; int action_tx_wait_time; + int action_tx_wait_time_used; int p2p_mgmt; @@ -856,11 +913,13 @@ struct wpa_supplicant { unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; + unsigned int p2p_go_do_acs:1; unsigned int p2p_persistent_group:1; unsigned int p2p_fallback_to_go_neg:1; unsigned int p2p_pd_before_go_neg:1; unsigned int p2p_go_ht40:1; unsigned int p2p_go_vht:1; + unsigned int p2p_go_he:1; unsigned int user_initiated_pd:1; unsigned int p2p_go_group_formation_completed:1; unsigned int group_formation_reported:1; @@ -871,6 +930,7 @@ struct wpa_supplicant { unsigned int p2p_disable_ip_addr_req:1; unsigned int p2ps_method_config_any:1; unsigned int p2p_cli_probe:1; + enum hostapd_hw_mode p2p_go_acs_band; int p2p_persistent_go_freq; int p2p_persistent_id; int p2p_go_intent; @@ -923,6 +983,7 @@ struct wpa_supplicant { int best_overall_freq; struct gas_query *gas; + struct gas_server *gas_server; #ifdef CONFIG_INTERWORKING unsigned int fetch_anqp_in_progress:1; @@ -966,6 +1027,10 @@ struct wpa_supplicant { /* WLAN_REASON_* reason codes. Negative if locally generated. */ int disconnect_reason; + /* WLAN_STATUS_* status codes from last received Authentication frame + * from the AP. */ + u16 auth_status_code; + /* WLAN_STATUS_* status codes from (Re)Association Response frame. */ u16 assoc_status_code; @@ -981,6 +1046,7 @@ struct wpa_supplicant { unsigned int wmm_ac_supported:1; unsigned int ext_work_in_progress:1; unsigned int own_disconnect_req:1; + unsigned int ignore_post_flush_scan_res:1; #define MAC_ADDR_RAND_SCAN BIT(0) #define MAC_ADDR_RAND_SCHED_SCAN BIT(1) @@ -1006,6 +1072,15 @@ struct wpa_supplicant { struct neighbor_report *wnm_neighbor_report_elements; struct os_reltime wnm_cand_valid_until; u8 wnm_cand_from_bss[ETH_ALEN]; + enum bss_trans_mgmt_status_code bss_tm_status; + struct wpabuf *coloc_intf_elems; + u8 coloc_intf_dialog_token; + u8 coloc_intf_auto_report; + u8 coloc_intf_timeout; +#ifdef CONFIG_MBO + unsigned int wnm_mbo_trans_reason_present:1; + u8 wnm_mbo_transition_reason; +#endif /* CONFIG_MBO */ #endif /* CONFIG_WNM */ #ifdef CONFIG_TESTING_GET_GTK @@ -1024,10 +1099,19 @@ struct wpa_supplicant { struct l2_packet_data *l2_test; unsigned int extra_roc_dur; enum wpa_supplicant_test_failure test_failure; + char *get_pref_freq_list_override; unsigned int reject_btm_req_reason; unsigned int p2p_go_csa_on_inv:1; unsigned int ignore_auth_resp:1; unsigned int ignore_assoc_disallow:1; + unsigned int testing_resend_assoc:1; + struct wpabuf *sae_commit_override; + enum wpa_alg last_tk_alg; + u8 last_tk_addr[ETH_ALEN]; + int last_tk_key_idx; + u8 last_tk[WPA_TK_MAX_LEN]; + size_t last_tk_len; + struct wpabuf *last_assoc_req_wpa_ie; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -1038,6 +1122,7 @@ struct wpa_supplicant { u8 last_tspecs_count; struct rrm_data rrm; + struct beacon_rep_data beacon_rep_data; #ifdef CONFIG_FST struct fst_iface *fst; @@ -1055,6 +1140,14 @@ struct wpa_supplicant { } *non_pref_chan; size_t non_pref_chan_num; u8 mbo_wnm_token; + /** + * enable_oce - Enable OCE if it is enabled by user and device also + * supports OCE. + * User can enable OCE with wpa_config's 'oce' parameter as follows - + * - Set BIT(0) to enable OCE in non-AP STA mode. + * - Set BIT(1) to enable OCE in STA-CFON mode. + */ + u8 enable_oce; #endif /* CONFIG_MBO */ /* @@ -1069,6 +1162,95 @@ struct wpa_supplicant { */ struct wpabuf *lci; struct os_reltime lci_time; + + struct os_reltime beacon_rep_scan; + + /* FILS HLP requests (struct fils_hlp_req) */ + struct dl_list fils_hlp_req; + + struct sched_scan_relative_params { + /** + * relative_rssi_set - Enable relatively preferred BSS reporting + * + * 0 = Disable reporting relatively preferred BSSs + * 1 = Enable reporting relatively preferred BSSs + */ + int relative_rssi_set; + + /** + * relative_rssi - Relative RSSI for reporting better BSSs + * + * Amount of RSSI by which a BSS should be better than the + * current connected BSS so that the new BSS can be reported + * to user space. This applies to sched_scan operations. + */ + int relative_rssi; + + /** + * relative_adjust_band - Band in which RSSI is to be adjusted + */ + enum set_band relative_adjust_band; + + /** + * relative_adjust_rssi - RSSI adjustment + * + * An amount of relative_adjust_rssi should be added to the + * BSSs that belong to the relative_adjust_band while comparing + * with other bands for BSS reporting. + */ + int relative_adjust_rssi; + } srp; + + /* RIC elements for FT protocol */ + struct wpabuf *ric_ies; + + int last_auth_timeout_sec; + +#ifdef CONFIG_DPP + struct dpp_global *dpp; + struct dpp_authentication *dpp_auth; + struct wpa_radio_work *dpp_listen_work; + unsigned int dpp_pending_listen_freq; + unsigned int dpp_listen_freq; + u8 dpp_allowed_roles; + int dpp_qr_mutual; + int dpp_netrole_ap; + int dpp_auth_ok_on_ack; + int dpp_in_response_listen; + int dpp_gas_client; + int dpp_gas_dialog_token; + u8 dpp_intro_bssid[ETH_ALEN]; + void *dpp_intro_network; + struct dpp_pkex *dpp_pkex; + struct dpp_bootstrap_info *dpp_pkex_bi; + char *dpp_pkex_code; + char *dpp_pkex_identifier; + char *dpp_pkex_auth_cmd; + char *dpp_configurator_params; + struct os_reltime dpp_last_init; + struct os_reltime dpp_init_iter_start; + unsigned int dpp_init_max_tries; + unsigned int dpp_init_retry_time; + unsigned int dpp_resp_wait_time; + unsigned int dpp_resp_max_tries; + unsigned int dpp_resp_retry_time; +#ifdef CONFIG_DPP2 + struct dpp_pfs *dpp_pfs; +#endif /* CONFIG_DPP2 */ +#ifdef CONFIG_TESTING_OPTIONS + char *dpp_config_obj_override; + char *dpp_discovery_override; + char *dpp_groups_override; + unsigned int dpp_ignore_netaccesskey_mismatch:1; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_DPP */ + +#ifdef CONFIG_FILS + unsigned int disable_fils:1; +#endif /* CONFIG_FILS */ + unsigned int ieee80211ac:1; + unsigned int enabled_4addr_mode:1; + unsigned int multi_bss_support:1; }; @@ -1101,6 +1283,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s); void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr); void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, int sec, int usec); +void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff); void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s); void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, enum wpa_states state); @@ -1158,6 +1341,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); +void fils_connection_failure(struct wpa_supplicant *wpa_s); int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s); int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason); @@ -1183,22 +1367,30 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, struct wpabuf *neighbor_rep), void *cb_ctx); void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, - const u8 *src, + const u8 *src, const u8 *dst, const u8 *frame, size_t len); void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *frame, size_t len, int rssi); +void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s); +int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res, + 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); /* MBO functions */ -int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len); +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len, + int add_oce_capa); +const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr); const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr); +const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, + enum mbo_attr_id attr); int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, const char *non_pref_chan); void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie); -int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos, - size_t len); void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie, size_t len); size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, @@ -1206,7 +1398,22 @@ size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, enum mbo_transition_reject_reason reason); void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa); struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss); + struct wpa_bss *bss, u32 mbo_subtypes); +void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, const u8 *sa, + const u8 *data, size_t slen); +void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s); + +/* op_classes.c */ +enum chan_allowed { + NOT_ALLOWED, NO_IR, ALLOWED +}; + +enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel, + u8 bw); +size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + int freq, u8 *pos, size_t len); /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response @@ -1238,6 +1445,9 @@ void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s); int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s); struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_ssid **selected_ssid); +int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, + struct channel_list_changed *info); /* eap_register.c */ int eap_register_methods(void); @@ -1290,12 +1500,22 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, u16 num_modes, enum hostapd_hw_mode mode); void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, - unsigned int sec); -int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid); + unsigned int sec, int rssi_threshold); +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); +void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s); struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_bss *bss, struct wpa_ssid *group, - int only_first_ssid); + int only_first_ssid, int debug_print); + +int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, + enum wpa_driver_if_type if_type, + unsigned int *num, + unsigned int *freq_list); + +int wpa_is_fils_supported(struct wpa_supplicant *wpa_s); +int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s); #endif /* WPA_SUPPLICANT_I_H */ diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf index f3f2a6417d2e..f55227f82685 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf @@ -4,3 +4,4 @@ eapol_version=1 ap_scan=1 fast_reauth=1 pmf=1 +p2p_add_cli_chan=1 diff --git a/contrib/wpa/wpa_supplicant/wpas_glue.c b/contrib/wpa/wpa_supplicant/wpas_glue.c index f84c8b90ac2f..449e04acded8 100644 --- a/contrib/wpa/wpa_supplicant/wpas_glue.c +++ b/contrib/wpa/wpa_supplicant/wpas_glue.c @@ -10,6 +10,7 @@ #include "common.h" #include "eapol_supp/eapol_supp_sm.h" +#include "eap_peer/eap.h" #include "rsn_supp/wpa.h" #include "eloop.h" #include "config.h" @@ -145,6 +146,8 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, * extra copy here */ 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 || wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { /* Current SSID is not using IEEE 802.1X/EAP, so drop possible * EAPOL frames (mainly, EAPOL-Start) from EAPOL state @@ -293,7 +296,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, } if (result != EAPOL_SUPP_RESULT_SUCCESS || - !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) return; if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) @@ -499,6 +502,16 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, wpa_s->last_gtk_len = key_len; } #endif /* CONFIG_TESTING_GET_GTK */ +#ifdef CONFIG_TESTING_OPTIONS + if (addr && !is_broadcast_ether_addr(addr)) { + wpa_s->last_tk_alg = alg; + os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN); + wpa_s->last_tk_key_idx = key_idx; + if (key) + os_memcpy(wpa_s->last_tk, key, key_len); + wpa_s->last_tk_len = key_len; + } +#endif /* CONFIG_TESTING_OPTIONS */ return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); } @@ -513,17 +526,74 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, } -static int wpa_supplicant_add_pmkid(void *wpa_s, - const u8 *bssid, const u8 *pmkid) +static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s, + void *network_ctx) { - return wpa_drv_add_pmkid(wpa_s, bssid, pmkid); + struct wpa_ssid *ssid; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (network_ctx == ssid) + return ssid; + } + + return NULL; } -static int wpa_supplicant_remove_pmkid(void *wpa_s, - const u8 *bssid, const u8 *pmkid) +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) { - return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid); + struct wpa_supplicant *wpa_s = _wpa_s; + struct wpa_ssid *ssid; + struct wpa_pmkid_params params; + + os_memset(¶ms, 0, sizeof(params)); + ssid = wpas_get_network_ctx(wpa_s, network_ctx); + if (ssid) + wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d", + MAC2STR(bssid), ssid->id); + if (ssid && fils_cache_id) { + params.ssid = ssid->ssid; + params.ssid_len = ssid->ssid_len; + params.fils_cache_id = fils_cache_id; + } else { + params.bssid = bssid; + } + + params.pmkid = pmkid; + params.pmk = pmk; + params.pmk_len = pmk_len; + + return wpa_drv_add_pmkid(wpa_s, ¶ms); +} + + +static int wpa_supplicant_remove_pmkid(void *_wpa_s, void *network_ctx, + const u8 *bssid, const u8 *pmkid, + const u8 *fils_cache_id) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + struct wpa_ssid *ssid; + struct wpa_pmkid_params params; + + os_memset(¶ms, 0, sizeof(params)); + ssid = wpas_get_network_ctx(wpa_s, network_ctx); + if (ssid) + wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_REMOVED MACSTR " %d", + MAC2STR(bssid), ssid->id); + if (ssid && fils_cache_id) { + params.ssid = ssid->ssid; + params.ssid_len = ssid->ssid_len; + params.fils_cache_id = fils_cache_id; + } else { + params.bssid = bssid; + } + + params.pmkid = pmkid; + + return wpa_drv_remove_pmkid(wpa_s, ¶ms); } @@ -865,12 +935,13 @@ static void wpa_supplicant_eap_param_needed(void *ctx, #ifdef CONFIG_EAP_PROXY + static void wpa_supplicant_eap_proxy_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; size_t len; - wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, + wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1, wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { wpa_s->imsi[len] = '\0'; @@ -880,6 +951,52 @@ static void wpa_supplicant_eap_proxy_cb(void *ctx) wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available"); } } + + +static void wpa_sm_sim_state_error_handler(struct wpa_supplicant *wpa_s) +{ + int i; + struct wpa_ssid *ssid; + const struct eap_method_type *eap_methods; + + if (!wpa_s->conf) + return; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + eap_methods = ssid->eap.eap_methods; + if (!eap_methods) + continue; + + for (i = 0; eap_methods[i].method != EAP_TYPE_NONE; i++) { + if (eap_methods[i].vendor == EAP_VENDOR_IETF && + (eap_methods[i].method == EAP_TYPE_SIM || + eap_methods[i].method == EAP_TYPE_AKA || + eap_methods[i].method == EAP_TYPE_AKA_PRIME)) { + wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); + break; + } + } + } +} + + +static void +wpa_supplicant_eap_proxy_notify_sim_status(void *ctx, + enum eap_proxy_sim_state sim_state) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status %u", sim_state); + switch (sim_state) { + case SIM_STATE_ERROR: + wpa_sm_sim_state_error_handler(wpa_s); + break; + default: + wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status unknown"); + break; + } +} + #endif /* CONFIG_EAP_PROXY */ @@ -921,6 +1038,14 @@ static void wpa_supplicant_status_cb(void *ctx, const char *status, } +static void wpa_supplicant_eap_error_cb(void *ctx, int error_code) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpas_notify_eap_error(wpa_s, error_code); +} + + static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) { struct wpa_supplicant *wpa_s = ctx; @@ -990,12 +1115,15 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->eap_param_needed = wpa_supplicant_eap_param_needed; #ifdef CONFIG_EAP_PROXY ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb; + ctx->eap_proxy_notify_sim_status = + wpa_supplicant_eap_proxy_notify_sim_status; #endif /* CONFIG_EAP_PROXY */ ctx->port_cb = wpa_supplicant_port_cb; ctx->cb = wpa_supplicant_eapol_cb; ctx->cert_cb = wpa_supplicant_cert_cb; 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->set_anon_id = wpa_supplicant_set_anon_id; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); @@ -1012,6 +1140,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) #ifndef CONFIG_NO_WPA + static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek, size_t kek_len, const u8 *kck, size_t kck_len, @@ -1035,6 +1164,34 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, else return 0; } + + +static void wpa_supplicant_fils_hlp_rx(void *ctx, const u8 *dst, const u8 *src, + const u8 *pkt, size_t pkt_len) +{ + struct wpa_supplicant *wpa_s = ctx; + char *hex; + size_t hexlen; + + hexlen = pkt_len * 2 + 1; + hex = os_malloc(hexlen); + if (!hex) + return; + wpa_snprintf_hex(hex, hexlen, pkt, pkt_len); + wpa_msg(wpa_s, MSG_INFO, FILS_HLP_RX "dst=" MACSTR " src=" MACSTR + " frame=%s", MAC2STR(dst), MAC2STR(src), hex); + os_free(hex); +} + + +static int wpa_supplicant_channel_info(void *_wpa_s, + struct wpa_channel_info *ci) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + + return wpa_drv_channel_info(wpa_s, ci); +} + #endif /* CONFIG_NO_WPA */ @@ -1084,6 +1241,8 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) #endif /* CONFIG_TDLS */ ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload; ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk; + ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx; + ctx->channel_info = wpa_supplicant_channel_info; wpa_s->wpa = wpa_sm_init(ctx); if (wpa_s->wpa == NULL) { @@ -1105,7 +1264,6 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, if (ssid) { os_memset(&conf, 0, sizeof(conf)); conf.network_ctx = ssid; - conf.peerkey_enabled = ssid->peerkey; conf.allowed_pairwise_cipher = ssid->pairwise_cipher; #ifdef IEEE8021X_EAPOL conf.proactive_key_caching = ssid->proactive_key_caching < 0 ? @@ -1133,6 +1291,11 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation; +#ifdef CONFIG_FILS + if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) + conf.fils_cache_id = + wpa_bss_get_fils_cache_id(wpa_s->current_bss); +#endif /* CONFIG_FILS */ } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); } diff --git a/contrib/wpa/wpa_supplicant/wpas_kay.c b/contrib/wpa/wpa_supplicant/wpas_kay.c index d6ec8c5090e9..41477d514d3f 100644 --- a/contrib/wpa/wpa_supplicant/wpas_kay.c +++ b/contrib/wpa/wpa_supplicant/wpas_kay.c @@ -5,7 +5,7 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include <openssl/ssl.h> + #include "utils/includes.h" #include "utils/common.h" @@ -38,12 +38,24 @@ static int wpas_macsec_deinit(void *priv) } +static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap) +{ + return wpa_drv_macsec_get_capability(priv, cap); +} + + static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled) { return wpa_drv_enable_protect_frames(wpa_s, enabled); } +static int wpas_enable_encrypt(void *wpa_s, Boolean enabled) +{ + return wpa_drv_enable_encrypt(wpa_s, enabled); +} + + static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window) { return wpa_drv_set_replay_protect(wpa_s, enabled, window); @@ -62,30 +74,27 @@ static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled) } -static int wpas_get_receive_lowest_pn(void *wpa_s, u32 channel, - u8 an, u32 *lowest_pn) +static int wpas_get_receive_lowest_pn(void *wpa_s, struct receive_sa *sa) { - return wpa_drv_get_receive_lowest_pn(wpa_s, channel, an, lowest_pn); + return wpa_drv_get_receive_lowest_pn(wpa_s, sa); } -static int wpas_get_transmit_next_pn(void *wpa_s, u32 channel, - u8 an, u32 *next_pn) +static int wpas_get_transmit_next_pn(void *wpa_s, struct transmit_sa *sa) { - return wpa_drv_get_transmit_next_pn(wpa_s, channel, an, next_pn); + return wpa_drv_get_transmit_next_pn(wpa_s, sa); } -static int wpas_set_transmit_next_pn(void *wpa_s, u32 channel, - u8 an, u32 next_pn) +static int wpas_set_transmit_next_pn(void *wpa_s, struct transmit_sa *sa) { - return wpa_drv_set_transmit_next_pn(wpa_s, channel, an, next_pn); + return wpa_drv_set_transmit_next_pn(wpa_s, sa); } -static int wpas_get_available_receive_sc(void *wpa_s, u32 *channel) +static int wpas_set_receive_lowest_pn(void *wpa_s, struct receive_sa *sa) { - return wpa_drv_get_available_receive_sc(wpa_s, channel); + return wpa_drv_set_receive_lowest_pn(wpa_s, sa); } @@ -103,83 +112,79 @@ static unsigned int conf_offset_val(enum confidentiality_offset co) } -static int wpas_create_receive_sc(void *wpa_s, u32 channel, - struct ieee802_1x_mka_sci *sci, +static int wpas_create_receive_sc(void *wpa_s, struct receive_sc *sc, enum validate_frames vf, enum confidentiality_offset co) { - return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, - be_to_host16(sci->port), - conf_offset_val(co), vf); + return wpa_drv_create_receive_sc(wpa_s, sc, conf_offset_val(co), vf); } -static int wpas_delete_receive_sc(void *wpa_s, u32 channel) +static int wpas_delete_receive_sc(void *wpa_s, struct receive_sc *sc) { - return wpa_drv_delete_receive_sc(wpa_s, channel); + return wpa_drv_delete_receive_sc(wpa_s, sc); } -static int wpas_create_receive_sa(void *wpa_s, u32 channel, u8 an, - u32 lowest_pn, const u8 *sak) +static int wpas_create_receive_sa(void *wpa_s, struct receive_sa *sa) { - return wpa_drv_create_receive_sa(wpa_s, channel, an, lowest_pn, sak); + return wpa_drv_create_receive_sa(wpa_s, sa); } -static int wpas_enable_receive_sa(void *wpa_s, u32 channel, u8 an) +static int wpas_delete_receive_sa(void *wpa_s, struct receive_sa *sa) { - return wpa_drv_enable_receive_sa(wpa_s, channel, an); + return wpa_drv_delete_receive_sa(wpa_s, sa); } -static int wpas_disable_receive_sa(void *wpa_s, u32 channel, u8 an) +static int wpas_enable_receive_sa(void *wpa_s, struct receive_sa *sa) { - return wpa_drv_disable_receive_sa(wpa_s, channel, an); + return wpa_drv_enable_receive_sa(wpa_s, sa); } -static int wpas_get_available_transmit_sc(void *wpa_s, u32 *channel) +static int wpas_disable_receive_sa(void *wpa_s, struct receive_sa *sa) { - return wpa_drv_get_available_transmit_sc(wpa_s, channel); + return wpa_drv_disable_receive_sa(wpa_s, sa); } static int -wpas_create_transmit_sc(void *wpa_s, u32 channel, - const struct ieee802_1x_mka_sci *sci, +wpas_create_transmit_sc(void *wpa_s, struct transmit_sc *sc, enum confidentiality_offset co) { - return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, - be_to_host16(sci->port), - conf_offset_val(co)); + return wpa_drv_create_transmit_sc(wpa_s, sc, conf_offset_val(co)); } -static int wpas_delete_transmit_sc(void *wpa_s, u32 channel) +static int wpas_delete_transmit_sc(void *wpa_s, struct transmit_sc *sc) { - return wpa_drv_delete_transmit_sc(wpa_s, channel); + return wpa_drv_delete_transmit_sc(wpa_s, sc); } -static int wpas_create_transmit_sa(void *wpa_s, u32 channel, u8 an, - u32 next_pn, Boolean confidentiality, - const u8 *sak) +static int wpas_create_transmit_sa(void *wpa_s, struct transmit_sa *sa) { - return wpa_drv_create_transmit_sa(wpa_s, channel, an, next_pn, - confidentiality, sak); + return wpa_drv_create_transmit_sa(wpa_s, sa); } -static int wpas_enable_transmit_sa(void *wpa_s, u32 channel, u8 an) +static int wpas_delete_transmit_sa(void *wpa_s, struct transmit_sa *sa) { - return wpa_drv_enable_transmit_sa(wpa_s, channel, an); + return wpa_drv_delete_transmit_sa(wpa_s, sa); } -static int wpas_disable_transmit_sa(void *wpa_s, u32 channel, u8 an) +static int wpas_enable_transmit_sa(void *wpa_s, struct transmit_sa *sa) { - return wpa_drv_disable_transmit_sa(wpa_s, channel, an); + return wpa_drv_enable_transmit_sa(wpa_s, sa); +} + + +static int wpas_disable_transmit_sa(void *wpa_s, struct transmit_sa *sa) +{ + return wpa_drv_disable_transmit_sa(wpa_s, sa); } @@ -194,7 +199,14 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) if (!ssid || ssid->macsec_policy == 0) return 0; - policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE; + if (ssid->macsec_policy == 1) { + if (ssid->macsec_integ_only == 1) + policy = SHOULD_SECURE; + else + policy = SHOULD_ENCRYPT; + } else { + policy = DO_NOT_SECURE; + } kay_ctx = os_zalloc(sizeof(*kay_ctx)); if (!kay_ctx) @@ -204,32 +216,36 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) kay_ctx->macsec_init = wpas_macsec_init; kay_ctx->macsec_deinit = wpas_macsec_deinit; + kay_ctx->macsec_get_capability = wpas_macsec_get_capability; kay_ctx->enable_protect_frames = wpas_enable_protect_frames; + kay_ctx->enable_encrypt = wpas_enable_encrypt; kay_ctx->set_replay_protect = wpas_set_replay_protect; kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite; kay_ctx->enable_controlled_port = wpas_enable_controlled_port; kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn; kay_ctx->get_transmit_next_pn = wpas_get_transmit_next_pn; kay_ctx->set_transmit_next_pn = wpas_set_transmit_next_pn; - kay_ctx->get_available_receive_sc = wpas_get_available_receive_sc; + kay_ctx->set_receive_lowest_pn = wpas_set_receive_lowest_pn; kay_ctx->create_receive_sc = wpas_create_receive_sc; kay_ctx->delete_receive_sc = wpas_delete_receive_sc; kay_ctx->create_receive_sa = wpas_create_receive_sa; + kay_ctx->delete_receive_sa = wpas_delete_receive_sa; kay_ctx->enable_receive_sa = wpas_enable_receive_sa; kay_ctx->disable_receive_sa = wpas_disable_receive_sa; - kay_ctx->get_available_transmit_sc = wpas_get_available_transmit_sc; kay_ctx->create_transmit_sc = wpas_create_transmit_sc; kay_ctx->delete_transmit_sc = wpas_delete_transmit_sc; kay_ctx->create_transmit_sa = wpas_create_transmit_sa; + kay_ctx->delete_transmit_sa = wpas_delete_transmit_sa; kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa; kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa; - res = ieee802_1x_kay_init(kay_ctx, policy, wpa_s->ifname, + res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect, + ssid->macsec_replay_window, ssid->macsec_port, + ssid->mka_priority, wpa_s->ifname, wpa_s->own_addr); - if (res == NULL) { - os_free(kay_ctx); + /* ieee802_1x_kay_init() frees kay_ctx on failure */ + if (res == NULL) return -1; - } wpa_s->kay = res; @@ -260,7 +276,7 @@ static int ieee802_1x_auth_get_session_id(struct wpa_supplicant *wpa_s, return -1; } - need_len = 1 + 2 * SSL3_RANDOM_SIZE; + need_len = 1 + 2 * 32 /* random size */; if (need_len > id_len) { wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough"); return -1; @@ -341,8 +357,8 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, /* Derive CAK from MSK */ cak->len = DEFAULT_KEY_LEN; - if (ieee802_1x_cak_128bits_aes_cmac(msk->key, wpa_s->own_addr, - peer_addr, cak->key)) { + if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, wpa_s->own_addr, + peer_addr, cak->key, cak->len)) { wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed"); goto fail; @@ -351,9 +367,8 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, /* Derive CKN from MSK */ ckn->len = DEFAULT_CKN_LEN; - if (ieee802_1x_ckn_128bits_aes_cmac(msk->key, wpa_s->own_addr, - peer_addr, sid, sid_len, - ckn->name)) { + if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, wpa_s->own_addr, + peer_addr, sid, sid_len, ckn->name)) { wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed"); goto fail; @@ -377,3 +392,49 @@ fail: return res; } + + +void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct mka_key *cak; + struct mka_key_name *ckn; + void *res = NULL; + + if ((ssid->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(wpa_s, ssid) < 0 || !wpa_s->kay) + goto free_cak; + + if (wpa_s->kay->policy == DO_NOT_SECURE) + goto dealloc; + + cak->len = ssid->mka_cak_len; + os_memcpy(cak->key, ssid->mka_cak, cak->len); + + ckn->len = ssid->mka_ckn_len; + os_memcpy(ckn->name, ssid->mka_ckn, ckn->len); + + res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE); + if (res) + goto free_cak; + +dealloc: + /* Failed to create MKA */ + ieee802_1x_dealloc_kay_sm(wpa_s); +free_cak: + os_free(cak); +free_ckn: + os_free(ckn); +end: + return res; +} diff --git a/contrib/wpa/wpa_supplicant/wpas_kay.h b/contrib/wpa/wpa_supplicant/wpas_kay.h index b7236d0776c4..81f8e0ce329e 100644 --- a/contrib/wpa/wpa_supplicant/wpas_kay.h +++ b/contrib/wpa/wpa_supplicant/wpas_kay.h @@ -17,6 +17,9 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, const u8 *peer_addr); void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s); +void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + #else /* CONFIG_MACSEC */ static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, @@ -36,6 +39,13 @@ static inline void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s) { } +static inline void * +ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + return 0; +} + #endif /* CONFIG_MACSEC */ #endif /* WPAS_KAY_H */ diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.c b/contrib/wpa/wpa_supplicant/wps_supplicant.c index 74a420c671d0..057927410256 100644 --- a/contrib/wpa/wpa_supplicant/wps_supplicant.c +++ b/contrib/wpa/wpa_supplicant/wps_supplicant.c @@ -203,6 +203,9 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s, if (ssid->ssid == NULL) return; bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len); + if (!bss) + bss = wpa_bss_get(wpa_s, wpa_s->bssid, + ssid->ssid, ssid->ssid_len); if (bss == NULL) { wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS " "table - use credential as-is"); @@ -490,6 +493,16 @@ static int wpa_supplicant_wps_cred(void *ctx, ssid->pairwise_cipher |= WPA_CIPHER_GCMP; ssid->group_cipher |= WPA_CIPHER_GCMP; } + if (wpa_s->drv_capa_known && + (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) { + ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256; + ssid->group_cipher |= WPA_CIPHER_GCMP_256; + } + if (wpa_s->drv_capa_known && + (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) { + ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256; + ssid->group_cipher |= WPA_CIPHER_CCMP_256; + } break; } @@ -517,11 +530,18 @@ static int wpa_supplicant_wps_cred(void *ctx, case WPS_AUTH_WPA2PSK: ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_PSK; + if (wpa_s->conf->wps_cred_add_sae && + cred->key_len != 2 * PMK_LEN) { + ssid->key_mgmt |= WPA_KEY_MGMT_SAE; +#ifdef CONFIG_IEEE80211W + ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; +#endif /* CONFIG_IEEE80211W */ + } ssid->proto = WPA_PROTO_RSN; break; } - if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) { + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { if (cred->key_len == 2 * PMK_LEN) { if (hexstr2bin((const char *) cred->key, ssid->psk, PMK_LEN)) { @@ -1027,10 +1047,9 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, continue; os_free(ssid->ssid); - ssid->ssid = os_malloc(bss->ssid_len); + ssid->ssid = os_memdup(bss->ssid, bss->ssid_len); if (ssid->ssid == NULL) break; - os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); ssid->ssid_len = bss->ssid_len; wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from " "scan results", @@ -1125,9 +1144,10 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, - int p2p_group) + int p2p_group, int multi_ap_backhaul_sta) { struct wpa_ssid *ssid; + char phase1[32]; #ifdef CONFIG_AP if (wpa_s->ap_iface) { @@ -1165,10 +1185,15 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, } } #endif /* CONFIG_P2P */ - if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0) + os_snprintf(phase1, sizeof(phase1), "pbc=1%s", + multi_ap_backhaul_sta ? " multi_ap=1" : ""); + if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0) return -1; if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; + if (multi_ap_backhaul_sta) + ssid->multi_ap_backhaul_sta = 1; + wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL); eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpas_wps_reassoc(wpa_s, ssid, bssid, 0); @@ -1481,6 +1506,9 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, wpa_s->global->ifaces->wps->uuid, WPS_UUID_LEN); src = "from the first interface"; + } else if (wpa_s->conf->auto_uuid == 1) { + uuid_random(wps->uuid); + src = "based on random data"; } else { uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); src = "based on MAC address"; diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.h b/contrib/wpa/wpa_supplicant/wps_supplicant.h index c8fe47e37279..0fbc85174f94 100644 --- a/contrib/wpa/wpa_supplicant/wps_supplicant.h +++ b/contrib/wpa/wpa_supplicant/wps_supplicant.h @@ -30,7 +30,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s); int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s); enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid); int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, - int p2p_group); + int p2p_group, int multi_ap_backhaul_sta); int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, int p2p_group, u16 dev_pw_id); void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s); |