diff options
author | Andrew Shadura <andrewsh@debian.org> | 2016-10-20 18:23:40 +0200 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2016-10-20 18:23:40 +0200 |
commit | 1e2b7568b4f69a9da79de660a1a04ef077479628 (patch) | |
tree | 252210229f2c2d4387457403887894a73eff4cf6 /wpa_supplicant | |
parent | aa5e2237f3bbd73853b3ffbb4bf693298c409792 (diff) |
Imported Upstream version 2.6
Diffstat (limited to 'wpa_supplicant')
107 files changed, 10586 insertions, 3468 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 0d818ed..a8d6a7f 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -49,6 +49,12 @@ ifeq ($(TARGET_ARCH),arm) L_CFLAGS += -mabi=aapcs-linux endif +# C++ flags for binder interface +L_CPPFLAGS := -std=c++11 -Wall -Werror +# TODO: Remove these allowed warnings later. +L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter +L_CPPFLAGS += -Wno-unused-private-field + INCLUDES = $(LOCAL_PATH) INCLUDES += $(LOCAL_PATH)/src INCLUDES += $(LOCAL_PATH)/src/common @@ -65,7 +71,6 @@ INCLUDES += $(LOCAL_PATH)/src/rsn_supp INCLUDES += $(LOCAL_PATH)/src/tls INCLUDES += $(LOCAL_PATH)/src/utils INCLUDES += $(LOCAL_PATH)/src/wps -INCLUDES += external/openssl/include INCLUDES += system/security/keystore/include ifdef CONFIG_DRIVER_NL80211 ifneq ($(wildcard external/libnl),) @@ -95,6 +100,7 @@ OBJS_p += src/utils/wpabuf.c OBJS_c = wpa_cli.c src/common/wpa_ctrl.c OBJS_c += src/utils/wpa_debug.c OBJS_c += src/utils/common.c +OBJS_c += src/common/cli.c OBJS_d = OBJS_priv = @@ -270,6 +276,7 @@ endif ifdef CONFIG_IBSS_RSN NEED_RSN_AUTHENTICATOR=y L_CFLAGS += -DCONFIG_IBSS_RSN +L_CFLAGS += -DCONFIG_NO_VLAN OBJS += ibss_rsn.c endif @@ -386,7 +393,6 @@ EAPDYN += src/eap_peer/eap_tls.so else L_CFLAGS += -DEAP_TLS OBJS += src/eap_peer/eap_tls.c -OBJS_h += src/eap_server/eap_server_tls.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -397,7 +403,6 @@ ifdef CONFIG_EAP_UNAUTH_TLS L_CFLAGS += -DEAP_UNAUTH_TLS ifndef CONFIG_EAP_TLS OBJS += src/eap_peer/eap_tls.c -OBJS_h += src/eap_server/eap_server_tls.c TLS_FUNCS=y endif CONFIG_IEEE8021X_EAPOL=y @@ -412,7 +417,6 @@ else L_CFLAGS += -DEAP_PEAP OBJS += src/eap_peer/eap_peap.c OBJS += src/eap_common/eap_peap_common.c -OBJS_h += src/eap_server/eap_server_peap.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -426,7 +430,6 @@ EAPDYN += src/eap_peer/eap_ttls.so else L_CFLAGS += -DEAP_TTLS OBJS += src/eap_peer/eap_ttls.c -OBJS_h += src/eap_server/eap_server_ttls.c endif TLS_FUNCS=y ifndef CONFIG_FIPS @@ -444,7 +447,6 @@ EAPDYN += src/eap_peer/eap_md5.so else L_CFLAGS += -DEAP_MD5 OBJS += src/eap_peer/eap_md5.c -OBJS_h += src/eap_server/eap_server_md5.c endif CHAP=y CONFIG_IEEE8021X_EAPOL=y @@ -467,7 +469,6 @@ else L_CFLAGS += -DEAP_MSCHAPv2 OBJS += src/eap_peer/eap_mschapv2.c OBJS += src/eap_peer/mschapv2.c -OBJS_h += src/eap_server/eap_server_mschapv2.c endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -481,7 +482,6 @@ EAPDYN += src/eap_peer/eap_gtc.so else L_CFLAGS += -DEAP_GTC OBJS += src/eap_peer/eap_gtc.c -OBJS_h += src/eap_server/eap_server_gtc.c endif CONFIG_IEEE8021X_EAPOL=y endif @@ -506,7 +506,6 @@ EAPDYN += src/eap_peer/eap_sim.so else L_CFLAGS += -DEAP_SIM OBJS += src/eap_peer/eap_sim.c -OBJS_h += src/eap_server/eap_server_sim.c endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y @@ -534,7 +533,6 @@ EAPDYN += src/eap_peer/eap_psk.so else L_CFLAGS += -DEAP_PSK OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c -OBJS_h += src/eap_server/eap_server_psk.c endif CONFIG_IEEE8021X_EAPOL=y NEED_AES=y @@ -551,7 +549,6 @@ EAPDYN += src/eap_peer/eap_aka.so else L_CFLAGS += -DEAP_AKA OBJS += src/eap_peer/eap_aka.c -OBJS_h += src/eap_server/eap_server_aka.c endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y @@ -577,7 +574,6 @@ endif ifdef CONFIG_EAP_SIM_COMMON OBJS += src/eap_common/eap_sim_common.c -OBJS_h += src/eap_server/eap_sim_db.c NEED_AES=y NEED_FIPS186_2_PRF=y endif @@ -592,7 +588,6 @@ else L_CFLAGS += -DEAP_FAST OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c OBJS += src/eap_common/eap_fast_common.c -OBJS_h += src/eap_server/eap_server_fast.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -607,7 +602,6 @@ EAPDYN += src/eap_peer/eap_pax.so else L_CFLAGS += -DEAP_PAX OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c -OBJS_h += src/eap_server/eap_server_pax.c endif CONFIG_IEEE8021X_EAPOL=y endif @@ -620,7 +614,6 @@ EAPDYN += src/eap_peer/eap_sake.so else L_CFLAGS += -DEAP_SAKE OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c -OBJS_h += src/eap_server/eap_server_sake.c endif CONFIG_IEEE8021X_EAPOL=y endif @@ -633,7 +626,6 @@ EAPDYN += src/eap_peer/eap_gpsk.so else L_CFLAGS += -DEAP_GPSK OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c -OBJS_h += src/eap_server/eap_server_gpsk.c endif CONFIG_IEEE8021X_EAPOL=y ifdef CONFIG_EAP_GPSK_SHA256 @@ -646,7 +638,6 @@ endif ifdef CONFIG_EAP_PWD L_CFLAGS += -DEAP_PWD OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c -OBJS_h += src/eap_server/eap_server_pwd.c CONFIG_IEEE8021X_EAPOL=y NEED_SHA256=y endif @@ -659,7 +650,6 @@ EAPDYN += src/eap_peer/eap_eke.so else L_CFLAGS += -DEAP_EKE OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c -OBJS_h += src/eap_server/eap_server_eke.c endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y @@ -682,7 +672,6 @@ OBJS += src/wps/wps_attr_process.c OBJS += src/wps/wps_dev_attr.c OBJS += src/wps/wps_enrollee.c OBJS += src/wps/wps_registrar.c -OBJS_h += src/eap_server/eap_server_wsc.c CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_SHA256=y @@ -745,8 +734,6 @@ else L_CFLAGS += -DEAP_IKEV2 OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c -OBJS_h += src/eap_server/eap_server_ikev2.c -OBJS_h += src/eap_server/ikev2.c endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y @@ -762,7 +749,6 @@ EAPDYN += src/eap_peer/eap_vendor_test.so else L_CFLAGS += -DEAP_VENDOR_TEST OBJS += src/eap_peer/eap_vendor_test.c -OBJS_h += src/eap_server/eap_server_vendor_test.c endif CONFIG_IEEE8021X_EAPOL=y endif @@ -772,8 +758,6 @@ ifdef CONFIG_EAP_TNC L_CFLAGS += -DEAP_TNC OBJS += src/eap_peer/eap_tnc.c OBJS += src/eap_peer/tncc.c -OBJS_h += src/eap_server/eap_server_tnc.c -OBJS_h += src/eap_server/tncs.c NEED_BASE64=y ifndef CONFIG_NATIVE_WINDOWS ifndef CONFIG_DRIVER_BSD @@ -820,6 +804,8 @@ OBJS += src/ap/ap_drv_ops.c OBJS += src/ap/beacon.c OBJS += src/ap/bss_load.c OBJS += src/ap/eap_user_db.c +OBJS += src/ap/neighbor_db.c +OBJS += src/ap/rrm.c ifdef CONFIG_IEEE80211N OBJS += src/ap/ieee802_11_ht.c ifdef CONFIG_IEEE80211AC @@ -829,6 +815,9 @@ endif ifdef CONFIG_WNM OBJS += src/ap/wnm_ap.c endif +ifdef CONFIG_MBO +OBJS += src/ap/mbo_ap.c +endif ifdef CONFIG_CTRL_IFACE OBJS += src/ap/ctrl_iface_ap.c endif @@ -845,6 +834,11 @@ L_CFLAGS += -DCONFIG_IEEE80211AC endif endif +ifdef CONFIG_MBO +OBJS += mbo.c +L_CFLAGS += -DCONFIG_MBO +endif + ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c @@ -880,34 +874,10 @@ OBJS += src/ap/peerkey_auth.c endif endif -ifdef CONFIG_EAP_SERVER -L_CFLAGS += -DEAP_SERVER -OBJS_h += src/eap_server/eap_server.c -OBJS_h += src/eap_server/eap_server_identity.c -OBJS_h += src/eap_server/eap_server_methods.c -endif - -ifdef CONFIG_RADIUS_CLIENT -OBJS_h += src/utils/ip_addr.c -OBJS_h += src/radius/radius.c -OBJS_h += src/radius/radius_client.c -endif - -ifdef CONFIG_AUTHENTICATOR -OBJS_h += src/eapol_auth/eapol_auth_sm.c -OBJS_h += src/ap/ieee802_1x.c -endif - -ifdef CONFIG_WPA_AUTHENTICATOR -OBJS_h += src/ap/wpa_auth.c -OBJS_h += src/ap/wpa_auth_ie.c -OBJS_h += src/ap/pmksa_cache_auth.c -ifdef CONFIG_IEEE80211R -OBJS_h += src/ap/wpa_auth_ft.c -endif -ifdef CONFIG_PEERKEY -OBJS_h += src/ap/peerkey_auth.c -endif +ifdef CONFIG_ACS +L_CFLAGS += -DCONFIG_ACS +OBJS += src/ap/acs.c +LIBS += -lm endif ifdef CONFIG_PCSC @@ -961,7 +931,6 @@ ifdef TLS_FUNCS NEED_DES=y # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST) OBJS += src/eap_peer/eap_tls_common.c -OBJS_h += src/eap_server/eap_server_tls_common.c ifndef CONFIG_FIPS NEED_TLS_PRF=y NEED_SHA1=y @@ -986,6 +955,7 @@ ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS L_CFLAGS += -DEAP_TLS_OPENSSL OBJS += src/crypto/tls_openssl.c +OBJS += src/crypto/tls_openssl_ocsp.c LIBS += -lssl endif OBJS += src/crypto/crypto_openssl.c @@ -1034,6 +1004,7 @@ OBJS += src/tls/tlsv1_cred.c OBJS += src/tls/tlsv1_client.c OBJS += src/tls/tlsv1_client_write.c OBJS += src/tls/tlsv1_client_read.c +OBJS += src/tls/tlsv1_client_ocsp.c OBJS += src/tls/asn1.c OBJS += src/tls/rsa.c OBJS += src/tls/x509v3.c @@ -1087,6 +1058,8 @@ CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif @@ -1273,10 +1246,19 @@ SHA256OBJS += src/crypto/sha256-prf.c ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += src/crypto/sha256-internal.c endif +ifdef CONFIG_INTERNAL_SHA384 +L_CFLAGS += -DCONFIG_INTERNAL_SHA384 +SHA256OBJS += src/crypto/sha384-internal.c +endif +ifdef CONFIG_INTERNAL_SHA512 +L_CFLAGS += -DCONFIG_INTERNAL_SHA512 +SHA256OBJS += src/crypto/sha512-internal.c +endif ifdef NEED_TLS_PRF_SHA256 SHA256OBJS += src/crypto/sha256-tlsprf.c endif ifdef NEED_HMAC_SHA256_KDF +L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF SHA256OBJS += src/crypto/sha256-kdf.c endif OBJS += $(SHA256OBJS) @@ -1319,6 +1301,7 @@ endif L_CFLAGS += -DCONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), unix) L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += src/common/ctrl_iface_common.c endif ifeq ($(CONFIG_CTRL_IFACE), udp) L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP @@ -1342,12 +1325,6 @@ ifdef CONFIG_WPS DBUS_OBJS += dbus/dbus_old_handlers_wps.c endif DBUS_OBJS += dbus/dbus_dict_helpers.c -ifndef DBUS_LIBS -DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) -endif -ifndef DBUS_INCLUDE -DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) -endif DBUS_CFLAGS += $(DBUS_INCLUDE) endif @@ -1363,12 +1340,6 @@ endif ifdef CONFIG_P2P DBUS_OBJS += dbus/dbus_new_handlers_p2p.c endif -ifndef DBUS_LIBS -DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) -endif -ifndef DBUS_INCLUDE -DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) -endif ifdef CONFIG_CTRL_IFACE_DBUS_INTRO DBUS_OBJS += dbus/dbus_new_introspect.c DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO @@ -1383,7 +1354,11 @@ endif OBJS += $(DBUS_OBJS) L_CFLAGS += $(DBUS_CFLAGS) -LIBS += $(DBUS_LIBS) + +ifdef CONFIG_CTRL_IFACE_BINDER +WPA_SUPPLICANT_USE_BINDER=y +L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER +endif ifdef CONFIG_READLINE OBJS_c += src/utils/edit_readline.c @@ -1529,12 +1504,6 @@ endif OBJS += src/drivers/driver_common.c -OBJS_wpa_rm := ctrl_iface.c ctrl_iface_unix.c -OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.c -ifdef CONFIG_AUTHENTICATOR -OBJS_wpa += tests/link_test.c -endif -OBJS_wpa += $(OBJS_l2) OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c OBJS_t += src/radius/radius_client.c @@ -1608,6 +1577,13 @@ endif ifeq ($(CONFIG_TLS), openssl) LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder 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),) LOCAL_SHARED_LIBRARIES += libnl @@ -1618,6 +1594,13 @@ endif LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(OBJS) LOCAL_C_INCLUDES := $(INCLUDES) +ifeq ($(DBUS), y) +LOCAL_SHARED_LIBRARIES += libdbus +endif +ifeq ($(WPA_SUPPLICANT_USE_BINDER), y) +LOCAL_SHARED_LIBRARIES += libbinder libutils +LOCAL_STATIC_LIBRARIES += libwpa_binder libwpa_binder_interface +endif include $(BUILD_EXECUTABLE) ######################## @@ -1656,3 +1639,42 @@ LOCAL_COPY_HEADERS_TO := libwpa_client LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h LOCAL_COPY_HEADERS += src/common/qca-vendor.h include $(BUILD_SHARED_LIBRARY) + +ifeq ($(WPA_SUPPLICANT_USE_BINDER), y) +### Binder interface library ### +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := libwpa_binder_interface +LOCAL_AIDL_INCLUDES := \ + $(LOCAL_PATH)/binder \ + frameworks/native/aidl/binder +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/binder +LOCAL_CPPFLAGS := $(L_CPPFLAGS) +LOCAL_SRC_FILES := \ + binder/binder_constants.cpp \ + binder/fi/w1/wpa_supplicant/ISupplicant.aidl \ + binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl \ + binder/fi/w1/wpa_supplicant/IIface.aidl +LOCAL_SHARED_LIBRARIES := libbinder +include $(BUILD_STATIC_LIBRARY) + +### Binder service library ### +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := libwpa_binder +LOCAL_CPPFLAGS := $(L_CPPFLAGS) +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_C_INCLUDES := $(INCLUDES) +LOCAL_SRC_FILES := \ + binder/binder.cpp binder/binder_manager.cpp \ + binder/supplicant.cpp binder/iface.cpp +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libutils +LOCAL_STATIC_LIBRARIES := libwpa_binder_interface +include $(BUILD_STATIC_LIBRARY) + +endif # BINDER == y diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog index facd90e..f28055f 100644 --- a/wpa_supplicant/ChangeLog +++ b/wpa_supplicant/ChangeLog @@ -1,5 +1,149 @@ ChangeLog for wpa_supplicant +2016-10-02 - v2.6 + * fixed WNM Sleep Mode processing when PMF is not enabled + [http://w1.fi/security/2015-6/] (CVE-2015-5310) + * fixed EAP-pwd last fragment validation + [http://w1.fi/security/2015-7/] (CVE-2015-5315) + * fixed EAP-pwd unexpected Confirm message processing + [http://w1.fi/security/2015-8/] (CVE-2015-5316) + * fixed WPS configuration update vulnerability with malformed passphrase + [http://w1.fi/security/2016-1/] (CVE-2016-4476) + * fixed configuration update vulnerability with malformed parameters set + over the local control interface + [http://w1.fi/security/2016-1/] (CVE-2016-4477) + * fixed TK configuration to the driver in EAPOL-Key 3/4 retry case + * extended channel switch support for P2P GO + * started to throttle control interface event message bursts to avoid + issues with monitor sockets running out of buffer space + * mesh mode fixes/improvements + - generate proper AID for peer + - enable WMM by default + - add VHT support + - fix PMKID derivation + - improve robustness on various exchanges + - fix peer link counting in reconnect case + - improve mesh joining behavior + - allow DTIM period to be configured + - allow HT to be disabled (disable_ht=1) + - add MESH_PEER_ADD and MESH_PEER_REMOVE commands + - add support for PMKSA caching + - add minimal support for SAE group negotiation + - allow pairwise/group cipher to be configured in the network profile + - use ieee80211w profile parameter to enable/disable PMF and derive + a separate TX IGTK if PMF is enabled instead of using MGTK + incorrectly + - fix AEK and MTK derivation + - remove GTKdata and IGTKdata from Mesh Peering Confirm/Close + - note: these changes are not fully backwards compatible for secure + (RSN) mesh network + * fixed PMKID derivation with SAE + * added support for requesting and fetching arbitrary ANQP-elements + without internal support in wpa_supplicant for the specific element + (anqp[265]=<hexdump> in "BSS <BSSID>" command output) + * P2P + - filter control characters in group client device names to be + consistent with other P2P peer cases + - support VHT 80+80 MHz and 160 MHz + - indicate group completion in P2P Client role after data association + instead of already after the WPS provisioning step + - improve group-join operation to use SSID, if known, to filter BSS + entries + - added optional ssid=<hexdump> argument to P2P_CONNECT for join case + - added P2P_GROUP_MEMBER command to fetch client interface address + * P2PS + - fix follow-on PD Response behavior + - fix PD Response generation for unknown peer + - fix persistent group reporting + - add channel policy to PD Request + - add group SSID to the P2PS-PROV-DONE event + - allow "P2P_CONNECT <addr> p2ps" to be used without specifying the + default PIN + * BoringSSL + - support for OCSP stapling + - support building of h20-osu-client + * D-Bus + - add ExpectDisconnect() + - add global config parameters as properties + - add SaveConfig() + - add VendorElemAdd(), VendorElemGet(), VendorElemRem() + * fixed Suite B 192-bit AKM to use proper PMK length + (note: this makes old releases incompatible with the fixed behavior) + * improved PMF behavior for cases where the AP and STA has different + configuration by not trying to connect in some corner cases where the + connection cannot succeed + * added option to reopen debug log (e.g., to rotate the file) upon + receipt of SIGHUP signal + * EAP-pwd: added support for Brainpool Elliptic Curves + (with OpenSSL 1.0.2 and newer) + * fixed EAPOL reauthentication after FT protocol run + * fixed FTIE generation for 4-way handshake after FT protocol run + * extended INTERFACE_ADD command to allow certain type (sta/ap) + interface to be created + * fixed and improved various FST operations + * added 80+80 MHz and 160 MHz VHT support for IBSS/mesh + * fixed SIGNAL_POLL in IBSS and mesh cases + * added an option to abort an ongoing scan (used to speed up connection + and can also be done with the new ABORT_SCAN command) + * TLS client + - do not verify CA certificates when ca_cert is not specified + - support validating server certificate hash + - support SHA384 and SHA512 hashes + - add signature_algorithms extension into ClientHello + - support TLS v1.2 signature algorithm with SHA384 and SHA512 + - support server certificate probing + - allow specific TLS versions to be disabled with phase2 parameter + - support extKeyUsage + - support PKCS #5 v2.0 PBES2 + - support PKCS #5 with PKCS #12 style key decryption + - minimal support for PKCS #12 + - support OCSP stapling (including ocsp_multi) + * OpenSSL + - support OpenSSL 1.1 API changes + - drop support for OpenSSL 0.9.8 + - drop support for OpenSSL 1.0.0 + * added support for multiple schedule scan plans (sched_scan_plans) + * added support for external server certificate chain validation + (tls_ext_cert_check=1 in the network profile phase1 parameter) + * made phase2 parser more strict about correct use of auth=<val> and + autheap=<val> values + * improved GAS offchannel operations with comeback request + * added SIGNAL_MONITOR command to request signal strength monitoring + events + * added command for retrieving HS 2.0 icons with in-memory storage + (REQ_HS20_ICON, GET_HS20_ICON, DEL_HS20_ICON commands and + RX-HS20-ICON event) + * enabled ACS support for AP mode operations with wpa_supplicant + * EAP-PEAP: fixed interoperability issue with Windows 2012r2 server + ("Invalid Compound_MAC in cryptobinding TLV") + * EAP-TTLS: fixed success after fragmented final Phase 2 message + * VHT: added interoperability workaround for 80+80 and 160 MHz channels + * WNM: workaround for broken AP operating class behavior + * added kqueue(2) support for eloop (CONFIG_ELOOP_KQUEUE) + * nl80211: + - add support for full station state operations + - do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled + - add NL80211_ATTR_PREV_BSSID with Connect command + - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use + unencrypted EAPOL frames + * added initial MBO support; number of extensions to WNM BSS Transition + Management + * added support for PBSS/PCP and P2P on 60 GHz + * Interworking: add credential realm to EAP-TLS identity + * fixed EAPOL-Key Request Secure bit to be 1 if PTK is set + * HS 2.0: add support for configuring frame filters + * added POLL_STA command to check connectivity in AP mode + * added initial functionality for location related operations + * started to ignore pmf=1/2 parameter for non-RSN networks + * added wps_disabled=1 network profile parameter to allow AP mode to + be started without enabling WPS + * wpa_cli: added action script support for AP-ENABLED and AP-DISABLED + events + * improved Public Action frame addressing + - add gas_address3 configuration parameter to control Address 3 + behavior + * number of small fixes + 2015-09-27 - v2.5 * fixed P2P validation of SSID element length before copying it [http://w1.fi/security/2015-1/] (CVE-2015-1863) diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index ad9ead9..f3e86c1 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -6,6 +6,17 @@ ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif +ifdef LIBS +# If LIBS is set with some global build system defaults, clone those for +# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well. +ifndef LIBS_c +LIBS_c := $(LIBS) +endif +ifndef LIBS_p +LIBS_p := $(LIBS) +endif +endif + export LIBDIR ?= /usr/local/lib/ export INCDIR ?= /usr/local/include/ export BINDIR ?= /usr/local/sbin/ @@ -17,6 +28,16 @@ CFLAGS += -I$(abspath ../src/utils) -include .config +ifndef CONFIG_NO_GITVER +# Add VERSION_STR postfix for builds from a git repository +ifeq ($(wildcard ../.git),../.git) +GITVER := $(shell git describe --dirty=+) +ifneq ($(GITVER),) +CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\" +endif +endif +endif + ifdef CONFIG_TESTING_OPTIONS CFLAGS += -DCONFIG_TESTING_OPTIONS CONFIG_WPS_TESTING=y @@ -89,6 +110,7 @@ OBJS_p += ../src/utils/wpabuf.o OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o OBJS_c += ../src/utils/wpa_debug.o OBJS_c += ../src/utils/common.o +OBJS_c += ../src/common/cli.o OBJS += wmm_ac.o ifndef CONFIG_OS @@ -149,6 +171,10 @@ ifdef CONFIG_ELOOP_EPOLL CFLAGS += -DCONFIG_ELOOP_EPOLL endif +ifdef CONFIG_ELOOP_KQUEUE +CFLAGS += -DCONFIG_ELOOP_KQUEUE +endif + ifdef CONFIG_EAPOL_TEST CFLAGS += -Werror -DEAPOL_TEST endif @@ -278,14 +304,23 @@ NEED_MD5=y NEED_RC4=y else CFLAGS += -DCONFIG_NO_WPA +ifeq ($(CONFIG_TLS), internal) +NEED_SHA1=y +NEED_MD5=y +endif endif ifdef CONFIG_IBSS_RSN NEED_RSN_AUTHENTICATOR=y CFLAGS += -DCONFIG_IBSS_RSN +CFLAGS += -DCONFIG_NO_VLAN OBJS += ibss_rsn.o endif +ifdef CONFIG_MATCH_IFACE +CFLAGS += -DCONFIG_MATCH_IFACE +endif + ifdef CONFIG_P2P OBJS += p2p_supplicant.o OBJS += p2p_supplicant_sd.o @@ -386,7 +421,6 @@ EAPDYN += ../src/eap_peer/eap_tls.so else CFLAGS += -DEAP_TLS OBJS += ../src/eap_peer/eap_tls.o -OBJS_h += ../src/eap_server/eap_server_tls.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -397,7 +431,6 @@ ifdef CONFIG_EAP_UNAUTH_TLS CFLAGS += -DEAP_UNAUTH_TLS ifndef CONFIG_EAP_TLS OBJS += ../src/eap_peer/eap_tls.o -OBJS_h += ../src/eap_server/eap_server_tls.o TLS_FUNCS=y endif CONFIG_IEEE8021X_EAPOL=y @@ -412,7 +445,6 @@ else CFLAGS += -DEAP_PEAP OBJS += ../src/eap_peer/eap_peap.o OBJS += ../src/eap_common/eap_peap_common.o -OBJS_h += ../src/eap_server/eap_server_peap.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -426,7 +458,6 @@ EAPDYN += ../src/eap_peer/eap_ttls.so else CFLAGS += -DEAP_TTLS OBJS += ../src/eap_peer/eap_ttls.o -OBJS_h += ../src/eap_server/eap_server_ttls.o endif TLS_FUNCS=y ifndef CONFIG_FIPS @@ -444,7 +475,6 @@ EAPDYN += ../src/eap_peer/eap_md5.so else CFLAGS += -DEAP_MD5 OBJS += ../src/eap_peer/eap_md5.o -OBJS_h += ../src/eap_server/eap_server_md5.o endif CHAP=y CONFIG_IEEE8021X_EAPOL=y @@ -467,7 +497,6 @@ else CFLAGS += -DEAP_MSCHAPv2 OBJS += ../src/eap_peer/eap_mschapv2.o OBJS += ../src/eap_peer/mschapv2.o -OBJS_h += ../src/eap_server/eap_server_mschapv2.o endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -481,7 +510,6 @@ EAPDYN += ../src/eap_peer/eap_gtc.so else CFLAGS += -DEAP_GTC OBJS += ../src/eap_peer/eap_gtc.o -OBJS_h += ../src/eap_server/eap_server_gtc.o endif CONFIG_IEEE8021X_EAPOL=y endif @@ -506,7 +534,6 @@ EAPDYN += ../src/eap_peer/eap_sim.so else CFLAGS += -DEAP_SIM OBJS += ../src/eap_peer/eap_sim.o -OBJS_h += ../src/eap_server/eap_server_sim.o endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y @@ -534,7 +561,6 @@ EAPDYN += ../src/eap_peer/eap_psk.so else CFLAGS += -DEAP_PSK OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o -OBJS_h += ../src/eap_server/eap_server_psk.o endif CONFIG_IEEE8021X_EAPOL=y NEED_AES=y @@ -551,7 +577,6 @@ EAPDYN += ../src/eap_peer/eap_aka.so else CFLAGS += -DEAP_AKA OBJS += ../src/eap_peer/eap_aka.o -OBJS_h += ../src/eap_server/eap_server_aka.o endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y @@ -577,7 +602,6 @@ endif ifdef CONFIG_EAP_SIM_COMMON OBJS += ../src/eap_common/eap_sim_common.o -OBJS_h += ../src/eap_server/eap_sim_db.o NEED_AES=y NEED_FIPS186_2_PRF=y endif @@ -592,7 +616,6 @@ else CFLAGS += -DEAP_FAST OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o OBJS += ../src/eap_common/eap_fast_common.o -OBJS_h += ../src/eap_server/eap_server_fast.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y @@ -607,7 +630,6 @@ EAPDYN += ../src/eap_peer/eap_pax.so else CFLAGS += -DEAP_PAX OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o -OBJS_h += ../src/eap_server/eap_server_pax.o endif CONFIG_IEEE8021X_EAPOL=y endif @@ -620,7 +642,6 @@ EAPDYN += ../src/eap_peer/eap_sake.so else CFLAGS += -DEAP_SAKE OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o -OBJS_h += ../src/eap_server/eap_server_sake.o endif CONFIG_IEEE8021X_EAPOL=y endif @@ -633,7 +654,6 @@ EAPDYN += ../src/eap_peer/eap_gpsk.so else CFLAGS += -DEAP_GPSK OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o -OBJS_h += ../src/eap_server/eap_server_gpsk.o endif CONFIG_IEEE8021X_EAPOL=y ifdef CONFIG_EAP_GPSK_SHA256 @@ -646,7 +666,6 @@ endif ifdef CONFIG_EAP_PWD CFLAGS += -DEAP_PWD OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o -OBJS_h += ../src/eap_server/eap_server_pwd.o CONFIG_IEEE8021X_EAPOL=y NEED_SHA256=y endif @@ -659,7 +678,6 @@ EAPDYN += ../src/eap_peer/eap_eke.so else CFLAGS += -DEAP_EKE OBJS += ../src/eap_peer/eap_eke.o ../src/eap_common/eap_eke_common.o -OBJS_h += ../src/eap_server/eap_server_eke.o endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y @@ -682,7 +700,6 @@ OBJS += ../src/wps/wps_attr_process.o OBJS += ../src/wps/wps_dev_attr.o OBJS += ../src/wps/wps_enrollee.o OBJS += ../src/wps/wps_registrar.o -OBJS_h += ../src/eap_server/eap_server_wsc.o CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_SHA256=y @@ -745,8 +762,6 @@ else CFLAGS += -DEAP_IKEV2 OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o -OBJS_h += ../src/eap_server/eap_server_ikev2.o -OBJS_h += ../src/eap_server/ikev2.o endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y @@ -762,7 +777,6 @@ EAPDYN += ../src/eap_peer/eap_vendor_test.so else CFLAGS += -DEAP_VENDOR_TEST OBJS += ../src/eap_peer/eap_vendor_test.o -OBJS_h += ../src/eap_server/eap_server_vendor_test.o endif CONFIG_IEEE8021X_EAPOL=y endif @@ -772,8 +786,6 @@ ifdef CONFIG_EAP_TNC CFLAGS += -DEAP_TNC OBJS += ../src/eap_peer/eap_tnc.o OBJS += ../src/eap_peer/tncc.o -OBJS_h += ../src/eap_server/eap_server_tnc.o -OBJS_h += ../src/eap_server/tncs.o NEED_BASE64=y ifndef CONFIG_NATIVE_WINDOWS ifndef CONFIG_DRIVER_BSD @@ -833,6 +845,8 @@ OBJS += ../src/ap/ap_drv_ops.o OBJS += ../src/ap/beacon.o OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/eap_user_db.o +OBJS += ../src/ap/neighbor_db.o +OBJS += ../src/ap/rrm.o ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o ifdef CONFIG_IEEE80211AC @@ -842,6 +856,9 @@ endif ifdef CONFIG_WNM OBJS += ../src/ap/wnm_ap.o endif +ifdef CONFIG_MBO +OBJS += ../src/ap/mbo_ap.o +endif ifdef CONFIG_CTRL_IFACE OBJS += ../src/ap/ctrl_iface_ap.o endif @@ -858,6 +875,11 @@ CFLAGS += -DCONFIG_IEEE80211AC endif endif +ifdef CONFIG_MBO +OBJS += mbo.o +CFLAGS += -DCONFIG_MBO +endif + ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o @@ -893,34 +915,10 @@ OBJS += ../src/ap/peerkey_auth.o endif endif -ifdef CONFIG_EAP_SERVER -CFLAGS += -DEAP_SERVER -OBJS_h += ../src/eap_server/eap_server.o -OBJS_h += ../src/eap_server/eap_server_identity.o -OBJS_h += ../src/eap_server/eap_server_methods.o -endif - -ifdef CONFIG_RADIUS_CLIENT -OBJS_h += ../src/utils/ip_addr.o -OBJS_h += ../src/radius/radius.o -OBJS_h += ../src/radius/radius_client.o -endif - -ifdef CONFIG_AUTHENTICATOR -OBJS_h += ../src/eapol_auth/eapol_auth_sm.o -OBJS_h += ../src/ap/ieee802_1x.o -endif - -ifdef CONFIG_WPA_AUTHENTICATOR -OBJS_h += ../src/ap/wpa_auth.o -OBJS_h += ../src/ap/wpa_auth_ie.o -OBJS_h += ../src/ap/pmksa_cache_auth.o -ifdef CONFIG_IEEE80211R -OBJS_h += ../src/ap/wpa_auth_ft.o -endif -ifdef CONFIG_PEERKEY -OBJS_h += ../src/ap/peerkey_auth.o -endif +ifdef CONFIG_ACS +CFLAGS += -DCONFIG_ACS +OBJS += ../src/ap/acs.o +LIBS += -lm endif ifdef CONFIG_PCSC @@ -933,9 +931,13 @@ ifdef CONFIG_NATIVE_WINDOWS #dynamic symbol loading that is now used in pcsc_funcs.c #LIBS += -lwinscard else +ifdef CONFIG_OSX +LIBS += -framework PCSC +else LIBS += -lpcsclite -lpthread endif endif +endif ifdef CONFIG_SIM_SIMULATOR CFLAGS += -DCONFIG_SIM_SIMULATOR @@ -974,7 +976,6 @@ ifdef TLS_FUNCS NEED_DES=y # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST) OBJS += ../src/eap_peer/eap_tls_common.o -OBJS_h += ../src/eap_server/eap_server_tls_common.o ifndef CONFIG_FIPS NEED_TLS_PRF=y NEED_SHA1=y @@ -999,6 +1000,7 @@ ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS CFLAGS += -DEAP_TLS_OPENSSL OBJS += ../src/crypto/tls_openssl.o +OBJS += ../src/crypto/tls_openssl_ocsp.o LIBS += -lssl endif OBJS += ../src/crypto/crypto_openssl.o @@ -1049,6 +1051,7 @@ OBJS += ../src/tls/tlsv1_cred.o OBJS += ../src/tls/tlsv1_client.o OBJS += ../src/tls/tlsv1_client_write.o OBJS += ../src/tls/tlsv1_client_read.o +OBJS += ../src/tls/tlsv1_client_ocsp.o OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o @@ -1102,6 +1105,8 @@ CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif @@ -1287,10 +1292,19 @@ SHA256OBJS += ../src/crypto/sha256-prf.o ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += ../src/crypto/sha256-internal.o endif +ifdef CONFIG_INTERNAL_SHA384 +CFLAGS += -DCONFIG_INTERNAL_SHA384 +SHA256OBJS += ../src/crypto/sha384-internal.o +endif +ifdef CONFIG_INTERNAL_SHA512 +CFLAGS += -DCONFIG_INTERNAL_SHA512 +SHA256OBJS += ../src/crypto/sha512-internal.o +endif ifdef NEED_TLS_PRF_SHA256 SHA256OBJS += ../src/crypto/sha256-tlsprf.o endif ifdef NEED_HMAC_SHA256_KDF +CFLAGS += -DCONFIG_HMAC_SHA256_KDF OBJS += ../src/crypto/sha256-kdf.o endif OBJS += $(SHA256OBJS) @@ -1333,6 +1347,7 @@ endif CFLAGS += -DCONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), unix) CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += ../src/common/ctrl_iface_common.o endif ifeq ($(CONFIG_CTRL_IFACE), udp) CFLAGS += -DCONFIG_CTRL_IFACE_UDP @@ -1374,6 +1389,7 @@ ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) endif DBUS_CFLAGS += $(DBUS_INCLUDE) +DBUS_INTERFACE=fi.epitest.hostap.WPASupplicant endif ifdef CONFIG_CTRL_IFACE_DBUS_NEW @@ -1399,6 +1415,7 @@ DBUS_OBJS += dbus/dbus_new_introspect.o DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO endif DBUS_CFLAGS += $(DBUS_INCLUDE) +DBUS_INTERFACE=fi.w1.wpa_supplicant1 endif ifdef DBUS @@ -1412,7 +1429,7 @@ LIBS += $(DBUS_LIBS) ifdef CONFIG_READLINE OBJS_c += ../src/utils/edit_readline.o -LIBS_c += -lncurses -lreadline +LIBS_c += -lreadline -lncurses else ifdef CONFIG_WPA_CLI_EDIT OBJS_c += ../src/utils/edit.o @@ -1443,6 +1460,10 @@ ifdef CONFIG_IPV6 CFLAGS += -DCONFIG_IPV6 endif +ifdef CONFIG_NO_LINUX_PACKET_SOCKET_WAR +CFLAGS += -DCONFIG_NO_LINUX_PACKET_SOCKET_WAR +endif + ifdef NEED_BASE64 OBJS += ../src/utils/base64.o endif @@ -1569,12 +1590,6 @@ endif OBJS += ../src/drivers/driver_common.o OBJS_priv += ../src/drivers/driver_common.o -OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o -OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o -ifdef CONFIG_AUTHENTICATOR -OBJS_wpa += tests/link_test.o -endif -OBJS_wpa += $(OBJS_l2) OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o OBJS_t += ../src/radius/radius_client.o @@ -1636,6 +1651,7 @@ endif OBJS += $(FST_OBJS) OBJS_t += $(FST_OBJS) OBJS_t2 += $(FST_OBJS) +OBJS_nfc += $(FST_OBJS) endif ifndef LDO @@ -1691,9 +1707,11 @@ wpa_cli: $(OBJS_c) LIBCTRL += ../src/common/wpa_ctrl.o LIBCTRL += ../src/utils/os_$(CONFIG_OS).o +LIBCTRL += ../src/utils/common.o LIBCTRL += ../src/utils/wpa_debug.o LIBCTRLSO += ../src/common/wpa_ctrl.c LIBCTRLSO += ../src/utils/os_$(CONFIG_OS).c +LIBCTRLSO += ../src/utils/common.c LIBCTRLSO += ../src/utils/wpa_debug.c libwpa_client.a: $(LIBCTRL) @@ -1705,12 +1723,12 @@ libwpa_client.so: $(LIBCTRLSO) @$(E) " CC $@ ($^)" $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^ -link_test: $(OBJS) $(OBJS_h) tests/link_test.o - $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS) +libwpa_test1: libwpa_test.o libwpa_client.a + $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 libwpa_test.o libwpa_client.a $(LIBS_c) @$(E) " LD " $@ -test_wpa: $(OBJS_wpa) $(OBJS_h) - $(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS) +libwpa_test2: libwpa_test.o libwpa_client.so + $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 libwpa_test.o -L. -lwpa_client $(LIBS_c) @$(E) " LD " $@ nfc_pw_token: $(OBJS_nfc) @@ -1760,11 +1778,13 @@ else endif %.service: %.service.in - $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ + $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \ + -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@ @$(E) " sed" $< %@.service: %.service.arg.in - $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ + $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \ + -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@ @$(E) " sed" $< wpa_supplicant.exe: wpa_supplicant @@ -1795,17 +1815,6 @@ wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm $(MAKE) -C wpa_gui-qt4 -TEST_EAP_SIM_COMMON_OBJS = $(SHA1OBJS) $(MD5OBJS) \ - ../src/utils/common.o ../src/utils/os_unix.o \ - ../src/utils/wpa_debug.o $(AESOBJS) \ - tests/test_eap_sim_common.o -test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS) - $(LDO) $(LDFLAGS) -o $@ $(TEST_EAP_SIM_COMMON_OBJS) $(LIBS) - ./test-eap_sim_common - rm test-eap_sim_common - -tests: test-eap_sim_common - FIPSDIR=/usr/local/ssl/fips-2.0 FIPSLD=$(FIPSDIR)/bin/fipsld fips: @@ -1826,5 +1835,6 @@ clean: rm -rf lcov-html rm -f libwpa_client.a rm -f libwpa_client.so + rm -f libwpa_test1 libwpa_test2 -include $(OBJS:%.o=%.d) diff --git a/wpa_supplicant/README b/wpa_supplicant/README index f9c65d2..11ab01a 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1,7 +1,7 @@ WPA Supplicant ============== -Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with @@ -72,11 +72,13 @@ Supported WPA/IEEE 802.11i features: * EAP-TTLS/CHAP * EAP-SIM * EAP-AKA + * EAP-AKA' * EAP-PSK * EAP-PAX * EAP-SAKE * EAP-IKEv2 * EAP-GPSK + * EAP-pwd * LEAP (note: requires special support from the driver for IEEE 802.11 authentication) (following methods are supported, but since they do not generate keying @@ -163,18 +165,12 @@ systems. In case of Windows builds, WinPcap is used by default Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS: -- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to +- OpenSSL (tested with 1.0.1 and 1.0.2 versions; assumed to work with most relatively recent versions; this is likely to be available with most distributions, http://www.openssl.org/) - GnuTLS - internal TLSv1 implementation -TLS options for EAP-FAST: -- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied - (i.e., the default OpenSSL package does not include support for - extensions needed for EAP-FAST) -- internal TLSv1 implementation - One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP implementation. A configuration file, .config, for compilation is @@ -308,7 +304,7 @@ Following build time configuration options are used to control IEEE 802.1X/EAPOL and EAP state machines and all EAP methods. Including TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL library for TLS implementation. Alternatively, GnuTLS or the internal -TLSv1 implementation can be used for TLS functionaly. +TLSv1 implementation can be used for TLS functionality. CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_MD5=y @@ -320,15 +316,17 @@ CONFIG_EAP_GTC=y CONFIG_EAP_OTP=y CONFIG_EAP_SIM=y CONFIG_EAP_AKA=y +CONFIG_EAP_AKA_PRIME=y CONFIG_EAP_PSK=y CONFIG_EAP_SAKE=y CONFIG_EAP_GPSK=y CONFIG_EAP_PAX=y CONFIG_EAP_LEAP=y CONFIG_EAP_IKEV2=y +CONFIG_EAP_PWD=y Following option can be used to include GSM SIM/USIM interface for GSM/UMTS -authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite +authentication algorithm (for EAP-SIM/EAP-AKA/EAP-AKA'). This requires pcsc-lite (http://www.linuxnet.com/) for smart card access. CONFIG_PCSC=y @@ -409,10 +407,10 @@ Command line options -------------------- usage: - wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \ + wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \ [-G<group>] \ -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \ - [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \ + [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \ [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ... options: @@ -435,8 +433,8 @@ options: -q = decrease debugging verbosity (-qq even less) -u = enable DBus control interface -v = show version - -w = wait for interface to be added, if needed -W = wait for a control interface monitor before starting + -M = start describing matching interface -N = start describing new interface -m = Configuration file for the P2P Device @@ -479,6 +477,22 @@ wpa_supplicant \ -c wpa2.conf -i wlan1 -D wext +If the interfaces on which wpa_supplicant is to run are not known or do +not exist, wpa_supplicant can match an interface when it arrives. Each +matched interface is separated with -M argument and the -i argument now +allows for pattern matching. + +As an example, the following command would start wpa_supplicant for a +specific wired interface called lan0, any interface starting with wlan +and lastly any other interface. Each match has its own configuration +file, and for the wired interface a specific driver has also been given. + +wpa_supplicant \ + -M -c wpa_wired.conf -ilan0 -D wired \ + -M -c wpa1.conf -iwlan* \ + -M -c wpa2.conf + + If the interface is added in a Linux bridge (e.g., br0), the bridge interface needs to be configured to wpa_supplicant in addition to the main interface: @@ -500,7 +514,7 @@ reloading can be triggered with 'wpa_cli reconfigure' command. Configuration file can include one or more network blocks, e.g., one for each used SSID. wpa_supplicant will automatically select the best -betwork based on the order of network blocks in the configuration +network based on the order of network blocks in the configuration file, network security level (WPA/WPA2 is preferred), and signal strength. @@ -792,7 +806,7 @@ addresses, etc. One wpa_cli process in "action" mode needs to be started for each interface. For example, the following command starts wpa_cli for the -default ingterface (-i can be used to select the interface in case of +default interface (-i can be used to select the interface in case of more than one interface being used at the same time): wpa_cli -a/sbin/wpa_action.sh -B @@ -1008,8 +1022,8 @@ event message is indicated that the external processing can start. Once the operation has been completed, "RADIO_WORK done <id>" is used to indicate that to wpa_supplicant. This allows other radio works to be performed. If this command is forgotten (e.g., due to the external -program terminating), wpa_supplicant will time out the radio owrk item -and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has +program terminating), wpa_supplicant will time out the radio work item +and send "EXT-RADIO-WORK-TIMEOUT <id>" event to indicate that this has happened. "RADIO_WORK done <id>" can also be used to cancel items that have not yet been started. diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 161dc06..e4eed20 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -229,7 +229,7 @@ Credentials can be pre-configured for automatic network selection: # # sp_priority: Credential priority within a provisioning SP # This is the priority of the credential among all credentials -# provisionined by the same SP (i.e., for entries that have identical +# provisioned by the same SP (i.e., for entries that have identical # provisioning_sp value). The range of this priority is 0-255 with 0 # being the highest and 255 the lower priority. # @@ -564,3 +564,68 @@ OK <3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list <3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List <3>ANQP fetch completed + + +Hotspot 2.0 Rel 2 online signup and OSEN +---------------------------------------- + +Following parameters can be used to create a network profile for +link-layer protected Hotspot 2.0 online signup connection with +OSEN. Note that ssid and identify (NAI) values need to be set based on +the information for the selected provider in the OSU Providers list +ANQP-element. + +network={ + ssid="HS 2.0 OSU" + proto=OSEN + key_mgmt=OSEN + pairwise=CCMP + group=GTK_NOT_USED + eap=WFA-UNAUTH-TLS + identity="anonymous@example.com" + ca_cert="osu-ca.pem" + ocsp=2 +} + + +Hotspot 2.0 connection with external network selection +------------------------------------------------------ + +When an 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 +SELECT_NETWORK control interface commands): + +interworking=1 +hs20=1 +auto_interworking=0 + +network={ + ssid="test-hs20" + proto=RSN + key_mgmt=WPA-EAP + pairwise=CCMP + anonymous_identity="anonymous@example.com" + identity="hs20-test@example.com" + password="password" + ca_cert="ca.pem" + eap=TTLS + phase2="auth=MSCHAPV2" + update_identifier=54321 + #ocsp=2 +} + + +These parameters are set based on the PPS MO credential and/or NAI Realm +list ANQP-element: + +anonymous_identity: Credential/UsernamePassword/Username with username part + replaced with "anonymous" +identity: Credential/UsernamePassword/Username +password: Credential/UsernamePassword/Password +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 +ocsp: Credential/CheckAAAServerCertStatus diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index 6a5b032..23ac7fa 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -151,6 +151,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] + [ssid=<hexdump>] Start P2P group formation with a discovered P2P peer. This includes optional group owner negotiation, group interface setup, provisioning, @@ -195,11 +196,17 @@ connection. out whether the peer device is operating as a GO and if so, use join-a-group operation rather than GO Negotiation. +"ssid=<hexdump>" can be used to specify the Group SSID for join +operations. This allows the P2P Client interface to filter scan results +based on SSID to avoid selecting an incorrect BSS entry in case the same +P2P Device or Interface address have been used in multiple groups +recently. + P2PS attribute changes to p2p_connect command: P2PS supports two WPS provisioning methods namely PIN method and P2PS default. -The remaining paramters hold same role as in legacy P2P. In case of P2PS default -config method "p2ps" keyword is added in p2p_connect command. +The remaining parameters hold same role as in legacy P2P. In case of P2PS +default config method "p2ps" keyword is added in p2p_connect command. For example: p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join @@ -281,7 +288,7 @@ group interface is used as a parameter for this command. p2p_cancel Cancel an ongoing P2P group formation and joining-a-group related -operation. This operations unauthorizes the specific peer device (if any +operation. This operation unauthorizes the specific peer device (if any had been authorized to start group formation), stops P2P find (if in progress), stops pending operations for join-a-group, and removes the P2P group interface (if one was used) that is in the WPS provisioning @@ -633,12 +640,17 @@ p2p_set managed <0/1> Disable/enable managed P2P Device operations. This is disabled by default. -p2p_set listen_channel <1/6/11> +p2p_set listen_channel <channel> [<op_class>] Set P2P Listen channel. This is mainly meant for testing purposes and changing the Listen channel during normal operations can result in protocol failures. +When specifying a social channel on the 2.4 GHz band (1/6/11) there is +no need to specify the operating class since it defaults to 81. When +specifying a social channel on the 60 GHz band (2), specify the 60 GHz +operating class (180). + p2p_set ssid_postfix <postfix> Set postfix string to be added to the automatically generated P2P SSID @@ -650,7 +662,7 @@ p2p_set per_sta_psk <0/1> Disabled(default)/enables use of per-client PSK in the P2P groups. This can be used to request GO to assign a unique PSK for each client during WPS provisioning. When enabled, this allow clients to be removed from -the group securily with p2p_remove_client command since that client's +the group securely with p2p_remove_client command since that client's PSK is removed at the same time to prevent it from connecting back using the old PSK. When per-client PSK is not used, the client can still be disconnected, but it will be able to re-join the group since the PSK it diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index 6c3ee6d..02505bb 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -32,6 +32,9 @@ #CONFIG_DRIVER_NL80211=y CONFIG_LIBNL20=y +# QCA vendor extensions to nl80211 +CONFIG_DRIVER_NL80211_QCA=y + # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) #CONFIG_DRIVER_BSD=y #CFLAGS += -I/usr/local/include @@ -92,7 +95,7 @@ CONFIG_EAP_TTLS=y # 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 +#CONFIG_EAP_FAST=y # EAP-GTC CONFIG_EAP_GTC=y @@ -321,6 +324,10 @@ CONFIG_IEEE80211W=y # Add introspection support for new DBus control interface #CONFIG_CTRL_IFACE_DBUS_INTRO=y +# Add support for Binder control interface +# Only applicable for Android platforms. +#CONFIG_CTRL_IFACE_BINDER=y + # Add support for loading EAP methods dynamically as shared libraries. # When this option is enabled, each EAP method can be either included # statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn). @@ -479,4 +486,7 @@ CONFIG_WIFI_DISPLAY=y # Enable Fast Session Transfer (FST) #CONFIG_FST=y +# Support Multi Band Operation +#CONFIG_MBO=y + include $(wildcard $(LOCAL_PATH)/android_config_*.inc) diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 7a4f4cf..5afb772 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -56,12 +56,32 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, if (!conf->secondary_channel) goto no_vht; - center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); + switch (conf->vht_oper_chwidth) { + case VHT_CHANWIDTH_80MHZ: + case VHT_CHANWIDTH_80P80MHZ: + center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); + break; + case VHT_CHANWIDTH_160MHZ: + center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel); + break; + default: + /* + * conf->vht_oper_chwidth might not be set for non-P2P GO cases, + * try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is + * not supported. + */ + conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ; + center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel); + if (!center_chan) { + conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ; + center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, + channel); + } + break; + } if (!center_chan) goto no_vht; - /* Use 80 MHz channel */ - conf->vht_oper_chwidth = 1; conf->vht_oper_centr_freq_seg0_idx = center_chan; return; @@ -72,14 +92,24 @@ no_vht: 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 */ -void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, - struct hostapd_config *conf) +int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct hostapd_config *conf) { + conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, + &conf->channel); + + if (conf->hw_mode == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz", + ssid->frequency); + return -1; + } + /* TODO: enable HT40 if driver supports it; * drop to 11b if driver does not support 11g */ @@ -166,6 +196,8 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, } } #endif /* CONFIG_IEEE80211N */ + + return 0; } @@ -179,15 +211,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface)); - conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, - &conf->channel); - if (conf->hw_mode == NUM_HOSTAPD_MODES) { - wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz", - ssid->frequency); + if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf)) + return -1; + + if (ssid->pbss > 1) { + wpa_printf(MSG_ERROR, "Invalid pbss value(%d) for AP mode", + ssid->pbss); return -1; } + bss->pbss = ssid->pbss; - wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf); +#ifdef CONFIG_ACS + if (ssid->acs) { + /* Setting channel to 0 in order to enable ACS */ + conf->channel = 0; + wpa_printf(MSG_DEBUG, "Use automatic channel selection"); + } +#endif /* CONFIG_ACS */ if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) { conf->ieee80211h = 1; @@ -229,12 +269,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; if (ssid->p2p_group) { - os_memcpy(bss->ip_addr_go, wpa_s->parent->conf->ip_addr_go, 4); - os_memcpy(bss->ip_addr_mask, wpa_s->parent->conf->ip_addr_mask, + os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4); + os_memcpy(bss->ip_addr_mask, wpa_s->p2pdev->conf->ip_addr_mask, 4); os_memcpy(bss->ip_addr_start, - wpa_s->parent->conf->ip_addr_start, 4); - os_memcpy(bss->ip_addr_end, wpa_s->parent->conf->ip_addr_end, + wpa_s->p2pdev->conf->ip_addr_start, 4); + os_memcpy(bss->ip_addr_end, wpa_s->p2pdev->conf->ip_addr_end, 4); } #endif /* CONFIG_P2P */ @@ -254,7 +294,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) bss->wpa = ssid->proto; - bss->wpa_key_mgmt = ssid->key_mgmt; + if (ssid->key_mgmt == DEFAULT_KEY_MGMT) + bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; + else + bss->wpa_key_mgmt = ssid->key_mgmt; bss->wpa_pairwise = ssid->pairwise_cipher; if (ssid->psk_set) { bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk)); @@ -263,6 +306,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, return -1; os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN); bss->ssid.wpa_psk->group = 1; + bss->ssid.wpa_psk_set = 1; } else if (ssid->passphrase) { bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase); } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] || @@ -297,13 +341,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, conf->beacon_int = wpa_s->conf->beacon_int; #ifdef CONFIG_P2P - if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) { - wpa_printf(MSG_INFO, - "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it", - wpa_s->conf->p2p_go_ctwindow, conf->beacon_int); - conf->p2p_go_ctwindow = 0; - } else { - conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow; + if (ssid->mode == WPAS_MODE_P2P_GO || + ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) { + if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) { + wpa_printf(MSG_INFO, + "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it", + wpa_s->conf->p2p_go_ctwindow, + conf->beacon_int); + conf->p2p_go_ctwindow = 0; + } else { + conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow; + } } #endif /* CONFIG_P2P */ @@ -372,6 +420,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, !(bss->wpa & 2))) goto no_wps; /* WPS2 does not allow WPA/TKIP-only * configuration */ + if (ssid->wps_disabled) + goto no_wps; bss->eap_server = 1; if (!ssid->ignore_broadcast_ssid) @@ -400,6 +450,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); os_memcpy(bss->os_version, wpa_s->conf->os_version, 4); bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1; + if (ssid->eap.fragment_size != DEFAULT_FRAGMENT_SIZE) + bss->fragment_size = ssid->eap.fragment_size; no_wps: #endif /* CONFIG_WPS */ @@ -416,6 +468,9 @@ no_wps: wpabuf_dup(wpa_s->conf->ap_vendor_elements); } + bss->ftm_responder = wpa_s->conf->ftm_responder; + bss->ftm_initiator = wpa_s->conf->ftm_initiator; + return 0; } @@ -448,14 +503,14 @@ static void ap_wps_event_cb(void *ctx, enum wps_event event, if (event == WPS_EV_FAIL) { struct wps_event_fail *fail = &data->fail; - if (wpa_s->parent && wpa_s->parent != wpa_s && + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s && wpa_s == wpa_s->global->p2p_group_formation) { /* * src/ap/wps_hostapd.c has already sent this on the * main interface, so only send on the parent interface * here if needed. */ - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); } @@ -530,6 +585,11 @@ static void wpas_ap_configured_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; +#ifdef CONFIG_ACS + if (wpa_s->current_ssid && wpa_s->current_ssid->acs) + wpa_s->assoc_freq = wpa_s->ap_iface->freq; +#endif /* CONFIG_ACS */ + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); if (wpa_s->ap_configured_cb) @@ -595,8 +655,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, params.p2p = 1; #endif /* CONFIG_P2P */ - if (wpa_s->parent->set_ap_uapsd) - params.uapsd = wpa_s->parent->ap_uapsd; + if (wpa_s->p2pdev->set_ap_uapsd) + params.uapsd = wpa_s->p2pdev->ap_uapsd; else if (params.p2p && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) params.uapsd = 1; /* mandatory for P2P GO */ else @@ -605,12 +665,17 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, if (ieee80211_is_dfs(params.freq.freq)) params.freq.freq = 0; /* set channel after CAC */ + if (params.p2p) + wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO); + else + wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS); + if (wpa_drv_associate(wpa_s, ¶ms) < 0) { wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality"); return -1; } - wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface)); + wpa_s->ap_iface = hapd_iface = hostapd_alloc_iface(); if (hapd_iface == NULL) return -1; hapd_iface->owner = wpa_s; @@ -627,6 +692,13 @@ 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)); @@ -668,7 +740,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, } hapd_iface->bss[i]->msg_ctx = wpa_s; - hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent; + hapd_iface->bss[i]->msg_ctx_parent = wpa_s->p2pdev; hapd_iface->bss[i]->public_action_cb = ap_public_action_rx; hapd_iface->bss[i]->public_action_cb_ctx = wpa_s; hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx; @@ -864,7 +936,10 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, return -1; if (pin == NULL) { - unsigned int rpin = wps_generate_pin(); + unsigned int rpin; + + if (wps_generate_pin(&rpin) < 0) + return -1; ret_len = os_snprintf(buf, buflen, "%08d", rpin); if (os_snprintf_error(buflen, ret_len)) return -1; @@ -930,7 +1005,8 @@ const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout) if (wpa_s->ap_iface == NULL) return NULL; hapd = wpa_s->ap_iface->bss[0]; - pin = wps_generate_pin(); + if (wps_generate_pin(&pin) < 0) + return NULL; os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin); os_free(hapd->conf->ap_pin); hapd->conf->ap_pin = os_strdup(pin_txt); @@ -1265,8 +1341,8 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, hapd = wpa_s->ap_iface->bss[0]; wps = hapd->wps; - if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL || - wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) { + if (wpa_s->p2pdev->conf->wps_nfc_dh_pubkey == NULL || + wpa_s->p2pdev->conf->wps_nfc_dh_privkey == NULL) { wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known"); return -1; } @@ -1275,9 +1351,9 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, wpabuf_free(wps->dh_pubkey); wpabuf_free(wps->dh_privkey); wps->dh_privkey = wpabuf_dup( - wpa_s->parent->conf->wps_nfc_dh_privkey); + wpa_s->p2pdev->conf->wps_nfc_dh_privkey); wps->dh_pubkey = wpabuf_dup( - wpa_s->parent->conf->wps_nfc_dh_pubkey); + wpa_s->p2pdev->conf->wps_nfc_dh_pubkey); if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) { wps->dh_ctx = NULL; wpabuf_free(wps->dh_pubkey); @@ -1308,6 +1384,58 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s) hapd = wpa_s->ap_iface->bss[0]; return hostapd_ctrl_iface_stop_ap(hapd); } + + +int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, + size_t len) +{ + size_t reply_len = 0, i; + char ap_delimiter[] = "---- AP ----\n"; + char mesh_delimiter[] = "---- mesh ----\n"; + size_t dlen; + + if (wpa_s->ap_iface) { + dlen = os_strlen(ap_delimiter); + if (dlen > len - reply_len) + return reply_len; + os_memcpy(&buf[reply_len], ap_delimiter, dlen); + reply_len += dlen; + + for (i = 0; i < wpa_s->ap_iface->num_bss; i++) { + reply_len += hostapd_ctrl_iface_pmksa_list( + wpa_s->ap_iface->bss[i], + &buf[reply_len], len - reply_len); + } + } + + if (wpa_s->ifmsh) { + dlen = os_strlen(mesh_delimiter); + if (dlen > len - reply_len) + return reply_len; + os_memcpy(&buf[reply_len], mesh_delimiter, dlen); + reply_len += dlen; + + reply_len += hostapd_ctrl_iface_pmksa_list( + wpa_s->ifmsh->bss[0], &buf[reply_len], + len - reply_len); + } + + return reply_len; +} + + +void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s) +{ + size_t i; + + if (wpa_s->ap_iface) { + for (i = 0; i < wpa_s->ap_iface->num_bss; i++) + hostapd_ctrl_iface_pmksa_flush(wpa_s->ap_iface->bss[i]); + } + + if (wpa_s->ifmsh) + hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]); +} #endif /* CONFIG_CTRL_IFACE */ diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 594168c..5a59ddc 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -76,12 +76,16 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, const struct wpabuf *pw, const u8 *pubkey_hash); struct hostapd_config; -void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, - struct hostapd_config *conf); +int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct hostapd_config *conf); 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); + void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, struct dfs_event *radar); void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c index a2cf7a5..072a1d5 100644 --- a/wpa_supplicant/autoscan.c +++ b/wpa_supplicant/autoscan.c @@ -1,6 +1,7 @@ /* * WPA Supplicant - auto scan * Copyright (c) 2012, Intel Corporation. All rights reserved. + * Copyright 2015 Intel Deutschland GmbH * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -15,13 +16,6 @@ #include "scan.h" #include "autoscan.h" -#ifdef CONFIG_AUTOSCAN_EXPONENTIAL -extern const struct autoscan_ops autoscan_exponential_ops; -#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */ - -#ifdef CONFIG_AUTOSCAN_PERIODIC -extern const struct autoscan_ops autoscan_periodic_ops; -#endif /* CONFIG_AUTOSCAN_PERIODIC */ static const struct autoscan_ops * autoscan_modules[] = { #ifdef CONFIG_AUTOSCAN_EXPONENTIAL @@ -50,6 +44,11 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) size_t nlen; int i; const struct autoscan_ops *ops = NULL; + struct sched_scan_plan *scan_plans; + + /* Give preference to scheduled scan plans if supported/configured */ + if (wpa_s->sched_scan_plans) + return 0; if (wpa_s->autoscan && wpa_s->autoscan_priv) return 0; @@ -79,11 +78,23 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) return -1; } + scan_plans = os_malloc(sizeof(*wpa_s->sched_scan_plans)); + if (!scan_plans) + return -1; + wpa_s->autoscan_params = NULL; wpa_s->autoscan_priv = ops->init(wpa_s, params); - if (wpa_s->autoscan_priv == NULL) + if (!wpa_s->autoscan_priv) { + os_free(scan_plans); return -1; + } + + scan_plans[0].interval = 5; + scan_plans[0].iterations = 0; + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = scan_plans; + wpa_s->sched_scan_plans_num = 1; wpa_s->autoscan = ops; wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with " @@ -116,7 +127,10 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s) wpa_s->autoscan_priv = NULL; wpa_s->scan_interval = 5; - wpa_s->sched_scan_interval = 0; + + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = NULL; + wpa_s->sched_scan_plans_num = 0; } } @@ -134,7 +148,7 @@ int autoscan_notify_scan(struct wpa_supplicant *wpa_s, return -1; wpa_s->scan_interval = interval; - wpa_s->sched_scan_interval = interval; + wpa_s->sched_scan_plans[0].interval = interval; request_scan(wpa_s); } diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h index e2a7652..560684f 100644 --- a/wpa_supplicant/autoscan.h +++ b/wpa_supplicant/autoscan.h @@ -27,6 +27,16 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s); int autoscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); +/* Available autoscan modules */ + +#ifdef CONFIG_AUTOSCAN_EXPONENTIAL +extern const struct autoscan_ops autoscan_exponential_ops; +#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */ + +#ifdef CONFIG_AUTOSCAN_PERIODIC +extern const struct autoscan_ops autoscan_periodic_ops; +#endif /* CONFIG_AUTOSCAN_PERIODIC */ + #else /* CONFIG_AUTOSCAN */ static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c index f74cdbf..798b43c 100644 --- a/wpa_supplicant/bgscan.c +++ b/wpa_supplicant/bgscan.c @@ -13,12 +13,6 @@ #include "config_ssid.h" #include "bgscan.h" -#ifdef CONFIG_BGSCAN_SIMPLE -extern const struct bgscan_ops bgscan_simple_ops; -#endif /* CONFIG_BGSCAN_SIMPLE */ -#ifdef CONFIG_BGSCAN_LEARN -extern const struct bgscan_ops bgscan_learn_ops; -#endif /* CONFIG_BGSCAN_LEARN */ static const struct bgscan_ops * bgscan_modules[] = { #ifdef CONFIG_BGSCAN_SIMPLE diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h index 9131e4e..3df1550 100644 --- a/wpa_supplicant/bgscan.h +++ b/wpa_supplicant/bgscan.h @@ -39,6 +39,15 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above, int current_signal, int current_noise, int current_txrate); +/* Available bgscan modules */ + +#ifdef CONFIG_BGSCAN_SIMPLE +extern const struct bgscan_ops bgscan_simple_ops; +#endif /* CONFIG_BGSCAN_SIMPLE */ +#ifdef CONFIG_BGSCAN_LEARN +extern const struct bgscan_ops bgscan_learn_ops; +#endif /* CONFIG_BGSCAN_LEARN */ + #else /* CONFIG_BGSCAN */ static inline int bgscan_init(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/binder/.clang-format b/wpa_supplicant/binder/.clang-format new file mode 100644 index 0000000..dbfdabf --- /dev/null +++ b/wpa_supplicant/binder/.clang-format @@ -0,0 +1,9 @@ +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Mozilla +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +AccessModifierOffset: -8 +AlignAfterOpenBracket: AlwaysBreak +SortIncludes: false diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp new file mode 100644 index 0000000..750e878 --- /dev/null +++ b/wpa_supplicant/binder/binder.cpp @@ -0,0 +1,104 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> + +#include "binder_manager.h" + +extern "C" { +#include "binder.h" +#include "binder_i.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/includes.h" +} + +void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_global *global = (wpa_global *)eloop_ctx; + struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx; + + wpa_printf( + MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd); + android::IPCThreadState::self()->handlePolledCommands(); +} + +struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global) +{ + struct wpas_binder_priv *priv; + wpa_supplicant_binder::BinderManager *binder_manager; + + priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv)); + if (!priv) + return NULL; + priv->global = global; + + android::ProcessState::self()->setThreadPoolMaxThreadCount(0); + android::IPCThreadState::self()->disableBackgroundScheduling(true); + android::IPCThreadState::self()->setupPolling(&priv->binder_fd); + wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd); + if (priv->binder_fd < 0) + goto err; + /* Look for read events from the binder socket in the eloop. */ + if (eloop_register_read_sock( + priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0) + goto err; + + binder_manager = wpa_supplicant_binder::BinderManager::getInstance(); + if (!binder_manager) + goto err; + binder_manager->registerBinderService(global); + /* We may not need to store this binder manager reference in the + * global data strucure because we've made it a singleton class. */ + priv->binder_manager = (void *)binder_manager; + + return priv; + +err: + wpas_binder_deinit(priv); + return NULL; +} + +void wpas_binder_deinit(struct wpas_binder_priv *priv) +{ + if (!priv) + return; + + wpa_supplicant_binder::BinderManager::destroyInstance(); + eloop_unregister_read_sock(priv->binder_fd); + android::IPCThreadState::shutdown(); +} + +int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->global->binder) + return 1; + + wpa_supplicant_binder::BinderManager *binder_manager = + wpa_supplicant_binder::BinderManager::getInstance(); + if (!binder_manager) + return 1; + + return binder_manager->registerInterface(wpa_s); +} + +int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->global->binder) + return 1; + + wpa_supplicant_binder::BinderManager *binder_manager = + wpa_supplicant_binder::BinderManager::getInstance(); + if (!binder_manager) + return 1; + + return binder_manager->unregisterInterface(wpa_s); +} diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h new file mode 100644 index 0000000..019e327 --- /dev/null +++ b/wpa_supplicant/binder/binder.h @@ -0,0 +1,46 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_H +#define WPA_SUPPLICANT_BINDER_BINDER_H + +#ifdef _cplusplus +extern "C" { +#endif /* _cplusplus */ + +/** + * This is the binder RPC interface entry point to the wpa_supplicant core. + * This initializes the binder driver & BinderManager instance and then forwards + * all the notifcations from the supplicant core to the BinderManager. + */ +struct wpas_binder_priv; +struct wpa_global; + +struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global); +void wpas_binder_deinit(struct wpas_binder_priv *priv); + +#ifdef CONFIG_CTRL_IFACE_BINDER +int wpas_binder_register_interface(struct wpa_supplicant *wpa_s); +int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s); +#else /* CONFIG_CTRL_IFACE_BINDER */ +static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} +static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} +#endif /* CONFIG_CTRL_IFACE_BINDER */ + +#ifdef _cplusplus +} +#endif /* _cplusplus */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */ diff --git a/wpa_supplicant/binder/binder_constants.cpp b/wpa_supplicant/binder/binder_constants.cpp new file mode 100644 index 0000000..0d452b1 --- /dev/null +++ b/wpa_supplicant/binder/binder_constants.cpp @@ -0,0 +1,18 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "binder_constants.h" + +namespace wpa_supplicant_binder { +namespace binder_constants { + +const char kServiceName[] = "wpa_supplicant"; + +} /* namespace binder_constants */ +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant/binder/binder_constants.h b/wpa_supplicant/binder/binder_constants.h new file mode 100644 index 0000000..a4d9b55 --- /dev/null +++ b/wpa_supplicant/binder/binder_constants.h @@ -0,0 +1,21 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H +#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H + +namespace wpa_supplicant_binder { +namespace binder_constants { + +extern const char kServiceName[]; + +} /* namespace binder_constants */ +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */ diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h new file mode 100644 index 0000000..5140d6d --- /dev/null +++ b/wpa_supplicant/binder/binder_i.h @@ -0,0 +1,28 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef BINDER_I_H +#define BINDER_I_H + +#ifdef _cplusplus +extern "C" { +#endif // _cplusplus + +struct wpas_binder_priv +{ + int binder_fd; + struct wpa_global *global; + void *binder_manager; +}; + +#ifdef _cplusplus +} +#endif /* _cplusplus */ + +#endif /* BINDER_I_H */ diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp new file mode 100644 index 0000000..27e8ded --- /dev/null +++ b/wpa_supplicant/binder/binder_manager.cpp @@ -0,0 +1,100 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include <binder/IServiceManager.h> + +#include "binder_constants.h" +#include "binder_manager.h" + +extern "C" { +#include "utils/common.h" +#include "utils/includes.h" +} + +namespace wpa_supplicant_binder { + +BinderManager *BinderManager::instance_ = NULL; + +BinderManager *BinderManager::getInstance() +{ + if (!instance_) + instance_ = new BinderManager(); + return instance_; +} + +void BinderManager::destroyInstance() +{ + if (instance_) + delete instance_; + instance_ = NULL; +} + +int BinderManager::registerBinderService(struct wpa_global *global) +{ + /* Create the main binder service object and register with + * system service manager. */ + supplicant_object_ = new Supplicant(global); + android::String16 service_name(binder_constants::kServiceName); + android::defaultServiceManager()->addService( + service_name, android::IInterface::asBinder(supplicant_object_)); + return 0; +} + +int BinderManager::registerInterface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s) + return 1; + + /* Using the corresponding wpa_supplicant pointer as key to our + * object map. */ + const void *iface_key = wpa_s; + + /* Return failure if we already have an object for that iface_key. */ + if (iface_object_map_.find(iface_key) != iface_object_map_.end()) + return 1; + + iface_object_map_[iface_key] = new Iface(wpa_s); + if (!iface_object_map_[iface_key].get()) + return 1; + + wpa_s->binder_object_key = iface_key; + + return 0; +} + +int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s || !wpa_s->binder_object_key) + return 1; + + const void *iface_key = wpa_s; + if (iface_object_map_.find(iface_key) == iface_object_map_.end()) + return 1; + + /* Delete the corresponding iface object from our map. */ + iface_object_map_.erase(iface_key); + wpa_s->binder_object_key = NULL; + return 0; +} + +int BinderManager::getIfaceBinderObjectByKey( + const void *iface_object_key, + android::sp<fi::w1::wpa_supplicant::IIface> *iface_object) +{ + if (!iface_object_key || !iface_object) + return 1; + + if (iface_object_map_.find(iface_object_key) == iface_object_map_.end()) + return 1; + + *iface_object = iface_object_map_[iface_object_key]; + return 0; +} + +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h new file mode 100644 index 0000000..d8b7dd0 --- /dev/null +++ b/wpa_supplicant/binder/binder_manager.h @@ -0,0 +1,58 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H +#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H + +#include <map> +#include <string> + +#include "iface.h" +#include "supplicant.h" + +struct wpa_global; +struct wpa_supplicant; + +namespace wpa_supplicant_binder { + +/** + * BinderManager is responsible for managing the lifetime of all + * binder objects created by wpa_supplicant. This is a singleton + * class which is created by the supplicant core and can be used + * to get references to the binder objects. + */ +class BinderManager +{ +public: + static BinderManager *getInstance(); + static void destroyInstance(); + int registerBinderService(struct wpa_global *global); + int registerInterface(struct wpa_supplicant *wpa_s); + int unregisterInterface(struct wpa_supplicant *wpa_s); + int getIfaceBinderObjectByKey( + const void *iface_object_key, + android::sp<fi::w1::wpa_supplicant::IIface> *iface_object); + +private: + BinderManager() = default; + ~BinderManager() = default; + + /* Singleton instance of this class. */ + static BinderManager *instance_; + /* The main binder service object. */ + android::sp<Supplicant> supplicant_object_; + /* Map of all the interface specific binder objects controlled by + * wpa_supplicant. This map is keyed in by the corresponding + * wpa_supplicant structure pointer. */ + std::map<const void *, android::sp<Iface>> iface_object_map_; +}; + +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */ diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl new file mode 100644 index 0000000..ea11d42 --- /dev/null +++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl @@ -0,0 +1,16 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +package fi.w1.wpa_supplicant; + +/** + * Interface exposed by wpa_supplicant for each network interface it controls. + */ +interface IIface { +} diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl new file mode 100644 index 0000000..1cbee20 --- /dev/null +++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl @@ -0,0 +1,59 @@ +/* + * WPA Supplicant - binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +package fi.w1.wpa_supplicant; + +import android.os.PersistableBundle; +import fi.w1.wpa_supplicant.IIface; + +/** + * Interface exposed by the wpa_supplicant binder service registered + * with the service manager with name: fi.w1.wpa_supplicant. + */ +interface ISupplicant { + /* Error values returned by the service to RPC method calls. */ + const int ERROR_INVALID_ARGS = 1; + const int ERROR_UNKNOWN = 2; + const int ERROR_IFACE_EXISTS = 3; + const int ERROR_IFACE_UNKNOWN = 4; + + /** + * Registers a wireless interface in wpa_supplicant. + * + * @param args A dictionary with arguments used to add the interface to + * wpa_supplicant. + * The dictionary may contain the following entries: + * Ifname(String) Name of the network interface to control, e.g., + * wlan0. + * BridgeIfname(String) Name of the bridge interface to control, e.g., + * br0. + * Driver(String) Driver name which the interface uses, e.g., nl80211. + * ConfigFile(String) Configuration file path. + * + * @return Binder object representing the interface. + */ + IIface CreateInterface(in PersistableBundle args); + + /** + * Deregisters a wireless interface from wpa_supplicant. + * + * @param ifname Name of the network interface, e.g., wlan0 + */ + void RemoveInterface(in @utf8InCpp String ifname); + + /** + * Gets a binder object for the interface corresponding to ifname + * which wpa_supplicant already controls. + * + * @param ifname Name of the network interface, e.g., wlan0 + * + * @return Binder object representing the interface. + */ + IIface GetInterface(in @utf8InCpp String ifname); +} diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl new file mode 100644 index 0000000..d624d91 --- /dev/null +++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl @@ -0,0 +1,20 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +package fi.w1.wpa_supplicant; + +import android.os.PersistableBundle; + +/** + * Callback Interface exposed by the wpa_supplicant service. Clients need + * to host an instance of this binder object and pass a reference of the object + * to wpa_supplicant via the registerCallbacksObject method. + */ +interface ISupplicantCallbacks { +} diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp new file mode 100644 index 0000000..c61b3b0 --- /dev/null +++ b/wpa_supplicant/binder/iface.cpp @@ -0,0 +1,16 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "iface.h" + +namespace wpa_supplicant_binder { + +Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {} + +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h new file mode 100644 index 0000000..c0ee12c --- /dev/null +++ b/wpa_supplicant/binder/iface.h @@ -0,0 +1,42 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_IFACE_H +#define WPA_SUPPLICANT_BINDER_IFACE_H + +#include "fi/w1/wpa_supplicant/BnIface.h" + +extern "C" { +#include "utils/common.h" +#include "utils/includes.h" +#include "../wpa_supplicant_i.h" +} + +namespace wpa_supplicant_binder { + +/** + * Implementation of Iface binder object. Each unique binder + * object is used for control operations on a specific interface + * controlled by wpa_supplicant. + */ +class Iface : public fi::w1::wpa_supplicant::BnIface +{ +public: + Iface(struct wpa_supplicant *wpa_s); + virtual ~Iface() = default; + +private: + /* Raw pointer to the structure maintained by the core for this + * interface. */ + struct wpa_supplicant *wpa_s_; +}; + +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */ diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp new file mode 100644 index 0000000..76569b1 --- /dev/null +++ b/wpa_supplicant/binder/supplicant.cpp @@ -0,0 +1,127 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "supplicant.h" +#include "binder_manager.h" + +namespace wpa_supplicant_binder { + +Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {} + +android::binder::Status Supplicant::CreateInterface( + const android::os::PersistableBundle ¶ms, + android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) +{ + android::String16 driver, ifname, confname, bridge_ifname; + + /* Check if required Ifname argument is missing */ + if (!params.getString(android::String16("Ifname"), &ifname)) + return android::binder::Status::fromServiceSpecificError( + ERROR_INVALID_ARGS, + android::String8("Ifname missing in params.")); + /* Retrieve the remaining params from the dictionary */ + params.getString(android::String16("Driver"), &driver); + params.getString(android::String16("ConfigFile"), &confname); + params.getString(android::String16("BridgeIfname"), &bridge_ifname); + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface( + wpa_global_, android::String8(ifname).string()) != NULL) + return android::binder::Status::fromServiceSpecificError( + ERROR_IFACE_EXISTS, + android::String8("wpa_supplicant already controls this " + "interface.")); + + android::binder::Status status; + struct wpa_supplicant *wpa_s = NULL; + struct wpa_interface iface; + + os_memset(&iface, 0, sizeof(iface)); + iface.driver = os_strdup(android::String8(driver).string()); + iface.ifname = os_strdup(android::String8(ifname).string()); + iface.confname = os_strdup(android::String8(confname).string()); + iface.bridge_ifname = + os_strdup(android::String8(bridge_ifname).string()); + /* Otherwise, have wpa_supplicant attach to it. */ + wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL); + /* The supplicant core creates a corresponding binder object via + * BinderManager when |wpa_supplicant_add_iface| is called. */ + if (!wpa_s || !wpa_s->binder_object_key) { + status = android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8( + "wpa_supplicant couldn't grab this interface.")); + } else { + BinderManager *binder_manager = BinderManager::getInstance(); + + if (!binder_manager || + binder_manager->getIfaceBinderObjectByKey( + wpa_s->binder_object_key, aidl_return)) + status = + android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8("wpa_supplicant encountered a " + "binder error.")); + else + status = android::binder::Status::ok(); + } + os_free((void *)iface.driver); + os_free((void *)iface.ifname); + os_free((void *)iface.confname); + os_free((void *)iface.bridge_ifname); + return status; +} + +android::binder::Status Supplicant::RemoveInterface(const std::string &ifname) +{ + struct wpa_supplicant *wpa_s; + + wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str()); + if (!wpa_s || !wpa_s->binder_object_key) + return android::binder::Status::fromServiceSpecificError( + ERROR_IFACE_UNKNOWN, + android::String8("wpa_supplicant does not control this " + "interface.")); + if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) + return android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8( + "wpa_supplicant couldn't remove this interface.")); + return android::binder::Status::ok(); +} + +android::binder::Status Supplicant::GetInterface( + const std::string &ifname, + android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) +{ + struct wpa_supplicant *wpa_s; + + wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str()); + if (!wpa_s || !wpa_s->binder_object_key) + return android::binder::Status::fromServiceSpecificError( + ERROR_IFACE_UNKNOWN, + android::String8( + "wpa_supplicant does not control this interface.")); + + BinderManager *binder_manager = BinderManager::getInstance(); + if (!binder_manager || + binder_manager->getIfaceBinderObjectByKey( + wpa_s->binder_object_key, aidl_return)) + return android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8( + "wpa_supplicant encountered a binder error.")); + + return android::binder::Status::ok(); +} + +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h new file mode 100644 index 0000000..136b99b --- /dev/null +++ b/wpa_supplicant/binder/supplicant.h @@ -0,0 +1,55 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H +#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H + +#include "fi/w1/wpa_supplicant/BnSupplicant.h" +#include "fi/w1/wpa_supplicant/IIface.h" +#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h" + +extern "C" { +#include "utils/common.h" +#include "utils/includes.h" +#include "../wpa_supplicant_i.h" +} + +namespace wpa_supplicant_binder { + +/** + * Implementation of the supplicant binder object. This binder + * object is used core for global control operations on + * wpa_supplicant. + */ +class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant +{ +public: + Supplicant(struct wpa_global *global); + virtual ~Supplicant() = default; + + android::binder::Status CreateInterface( + const android::os::PersistableBundle ¶ms, + android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override; + android::binder::Status + RemoveInterface(const std::string &ifname) override; + android::binder::Status GetInterface( + const std::string &ifname, + android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override; + +private: + /* Raw pointer to the global structure maintained by the core. */ + struct wpa_global *wpa_global_; + /* All the callback objects registered by the clients. */ + std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>> + callbacks_; +}; + +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */ diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 1051ee3..3a8778d 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -12,6 +12,7 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "drivers/driver.h" +#include "eap_peer/eap.h" #include "wpa_supplicant_i.h" #include "config.h" #include "notify.h" @@ -60,6 +61,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void) anqp = os_zalloc(sizeof(*anqp)); if (anqp == NULL) return NULL; +#ifdef CONFIG_INTERWORKING + dl_list_init(&anqp->anqp_elems); +#endif /* CONFIG_INTERWORKING */ anqp->users = 1; return anqp; } @@ -80,6 +84,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f) #ifdef CONFIG_INTERWORKING + dl_list_init(&n->anqp_elems); ANQP_DUP(capability_list); ANQP_DUP(venue_name); ANQP_DUP(network_auth_type); @@ -141,6 +146,10 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss) */ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) { +#ifdef CONFIG_INTERWORKING + struct wpa_bss_anqp_elem *elem; +#endif /* CONFIG_INTERWORKING */ + if (anqp == NULL) return; @@ -159,6 +168,13 @@ 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); + + while ((elem = dl_list_first(&anqp->anqp_elems, + struct wpa_bss_anqp_elem, list))) { + dl_list_del(&elem->list); + wpabuf_free(elem->payload); + os_free(elem); + } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 wpabuf_free(anqp->hs20_capability_list); @@ -198,8 +214,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, } -static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - const char *reason) +void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const char *reason) { if (wpa_s->last_scan_res) { unsigned int i; @@ -288,6 +304,47 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, } +static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ +#ifdef CONFIG_WPS + struct wpa_ssid *ssid; + struct wpabuf *wps_ie; + int pbc = 0, ret; + + wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (!wps_ie) + return 0; + + if (wps_is_selected_pbc_registrar(wps_ie)) { + pbc = 1; + } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) { + wpabuf_free(wps_ie); + return 0; + } + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) + continue; + if (ssid->ssid_len && + (ssid->ssid_len != bss->ssid_len || + os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0)) + continue; + + if (pbc) + ret = eap_is_wps_pbc_enrollee(&ssid->eap); + else + ret = eap_is_wps_pin_enrollee(&ssid->eap); + wpabuf_free(wps_ie); + return ret; + } + wpabuf_free(wps_ie); +#endif /* CONFIG_WPS */ + + return 0; +} + + static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_ssid *ssid; @@ -326,7 +383,8 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { - if (!wpa_bss_known(wpa_s, bss)) { + if (!wpa_bss_known(wpa_s, bss) && + !wpa_bss_is_wps_candidate(wpa_s, bss)) { wpa_bss_remove(wpa_s, bss, __func__); return 0; } @@ -784,7 +842,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, struct wpa_bss *bss, *n; os_get_reltime(&wpa_s->last_scan); - if (!new_scan) + if ((info && info->aborted) || !new_scan) return; /* do not expire entries without new scan */ dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { @@ -1004,20 +1062,7 @@ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s, */ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) { - const u8 *end, *pos; - - pos = (const u8 *) (bss + 1); - end = pos + bss->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; + return get_ie((const u8 *) (bss + 1), bss->ie_len, ie); } @@ -1037,8 +1082,8 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1074,8 +1119,8 @@ const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss, pos += bss->ie_len; end = pos + bss->beacon_ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1110,8 +1155,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1155,8 +1200,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, pos += bss->ie_len; end = pos + bss->beacon_ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index b215380..84e8fb0 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -19,6 +19,12 @@ struct wpa_scan_res; #define WPA_BSS_ASSOCIATED BIT(5) #define WPA_BSS_ANQP_FETCH_TRIED BIT(6) +struct wpa_bss_anqp_elem { + struct dl_list list; + u16 infoid; + struct wpabuf *payload; +}; + /** * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss) */ @@ -34,6 +40,7 @@ struct wpa_bss_anqp { struct wpabuf *nai_realm; struct wpabuf *anqp_3gpp; struct wpabuf *domain_name; + struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */ #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 struct wpabuf *hs20_capability_list; @@ -106,6 +113,8 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, struct os_reltime *fetch_time); +void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const char *reason); void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan); int wpa_bss_init(struct wpa_supplicant *wpa_s); @@ -141,6 +150,17 @@ static inline int bss_is_dmg(const struct wpa_bss *bss) return bss->freq > 45000; } +/** + * Test whether a BSS is a PBSS. + * This checks whether a BSS is a DMG-band PBSS. PBSS is used for P2P DMG + * network. + */ +static inline int bss_is_pbss(struct wpa_bss *bss) +{ + return bss_is_dmg(bss) && + (bss->caps & IEEE80211_CAP_DMG_MASK) == IEEE80211_CAP_DMG_PBSS; +} + static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level) { if (bss != NULL && new_level < 0) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b1adab7..dd922ca 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -32,7 +32,11 @@ struct parse_data { /* Configuration variable name */ char *name; - /* Parser function for this variable */ + /* Parser function for this variable. The parser functions return 0 or 1 + * to indicate success. Value 0 indicates that the parameter value may + * have changed while value 1 means that the value did not change. + * Error cases (failure to parse the string) are indicated by returning + * -1. */ int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value); @@ -59,7 +63,7 @@ static int wpa_config_parse_str(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { - size_t res_len, *dst_len; + size_t res_len, *dst_len, prev_len; char **dst, *tmp; if (os_strcmp(value, "NULL") == 0) { @@ -105,6 +109,21 @@ static int wpa_config_parse_str(const struct parse_data *data, set: dst = (char **) (((u8 *) ssid) + (long) data->param1); dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); + + if (data->param2) + prev_len = *dst_len; + else if (*dst) + prev_len = os_strlen(*dst); + else + prev_len = 0; + if ((*dst == NULL && tmp == NULL) || + (*dst && tmp && prev_len == res_len && + os_memcmp(*dst, tmp, res_len) == 0)) { + /* No change to the previously configured value */ + os_free(tmp); + return 1; + } + os_free(*dst); *dst = tmp; if (data->param2) @@ -190,6 +209,9 @@ static int wpa_config_parse_int(const struct parse_data *data, line, value); return -1; } + + if (*dst == val) + return 1; *dst = val; wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); @@ -456,9 +478,17 @@ static int wpa_config_parse_psk(const struct parse_data *data, } wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", (u8 *) value, len); + if (has_ctrl_char((u8 *) value, len)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid passphrase character", + line); + return -1; + } if (ssid->passphrase && os_strlen(ssid->passphrase) == len && - os_memcmp(ssid->passphrase, value, len) == 0) - return 0; + os_memcmp(ssid->passphrase, value, len) == 0) { + /* No change to the previously configured value */ + return 1; + } ssid->psk_set = 0; str_clear_free(ssid->passphrase); ssid->passphrase = dup_binstr(value, len); @@ -569,6 +599,8 @@ static int wpa_config_parse_proto(const struct parse_data *data, errors++; } + if (!errors && ssid->proto == val) + return 1; wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); ssid->proto = val; return errors ? -1 : 0; @@ -705,6 +737,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, errors++; } + if (!errors && ssid->key_mgmt == val) + return 1; wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); ssid->key_mgmt = val; return errors ? -1 : 0; @@ -899,6 +933,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, static int wpa_config_parse_cipher(int line, const char *value) { +#ifdef CONFIG_NO_WPA + return -1; +#else /* CONFIG_NO_WPA */ int val = wpa_parse_cipher(value); if (val < 0) { wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", @@ -911,12 +948,16 @@ static int wpa_config_parse_cipher(int line, const char *value) return -1; } return val; +#endif /* CONFIG_NO_WPA */ } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_cipher(int cipher) { +#ifdef CONFIG_NO_WPA + return NULL; +#else /* CONFIG_NO_WPA */ char *buf = os_zalloc(50); if (buf == NULL) return NULL; @@ -927,6 +968,7 @@ static char * wpa_config_write_cipher(int cipher) } return buf; +#endif /* CONFIG_NO_WPA */ } #endif /* NO_CONFIG_WRITE */ @@ -945,6 +987,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data, return -1; } + if (ssid->pairwise_cipher == val) + return 1; wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); ssid->pairwise_cipher = val; return 0; @@ -981,6 +1025,8 @@ static int wpa_config_parse_group(const struct parse_data *data, return -1; } + if (ssid->group_cipher == val) + return 1; wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); ssid->group_cipher = val; return 0; @@ -1042,6 +1088,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data, errors++; } + if (!errors && ssid->auth_alg == val) + return 1; wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); ssid->auth_alg = val; return errors ? -1 : 0; @@ -1296,6 +1344,32 @@ static int wpa_config_parse_eap(const struct parse_data *data, methods[num_methods].method = EAP_TYPE_NONE; num_methods++; + if (!errors && ssid->eap.eap_methods) { + struct eap_method_type *prev_m; + size_t i, j, prev_methods, match = 0; + + prev_m = ssid->eap.eap_methods; + for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF || + prev_m[i].method != EAP_TYPE_NONE; i++) { + /* Count the methods */ + } + prev_methods = i + 1; + + for (i = 0; prev_methods == num_methods && i < prev_methods; + i++) { + for (j = 0; j < num_methods; j++) { + if (prev_m[i].vendor == methods[j].vendor && + prev_m[i].method == methods[j].method) { + match++; + break; + } + } + } + if (match == num_methods) { + os_free(methods); + return 1; + } + } wpa_hexdump(MSG_MSGDUMP, "eap methods", (u8 *) methods, num_methods * sizeof(*methods)); os_free(ssid->eap.eap_methods); @@ -1348,6 +1422,8 @@ static int wpa_config_parse_password(const struct parse_data *data, u8 *hash; if (os_strcmp(value, "NULL") == 0) { + if (!ssid->eap.password) + return 1; /* Already unset */ wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); bin_clear_free(ssid->eap.password, ssid->eap.password_len); ssid->eap.password = NULL; @@ -1411,6 +1487,12 @@ static int wpa_config_parse_password(const struct parse_data *data, wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); + if (ssid->eap.password && ssid->eap.password_len == 16 && + os_memcmp(ssid->eap.password, hash, 16) == 0 && + (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { + bin_clear_free(hash, 16); + return 1; + } bin_clear_free(ssid->eap.password, ssid->eap.password_len); ssid->eap.password = hash; ssid->eap.password_len = 16; @@ -1837,6 +1919,8 @@ static const struct parse_data ssid_fields[] = { { FUNC(auth_alg) }, { FUNC(scan_freq) }, { FUNC(freq_list) }, + { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT, + VHT_CHANWIDTH_80P80MHZ) }, #ifdef IEEE8021X_EAPOL { FUNC(eap) }, { STR_LENe(identity) }, @@ -1910,6 +1994,9 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(mixed_cell, 0, 1) }, { INT_RANGE(frequency, 0, 65000) }, { INT_RANGE(fixed_freq, 0, 1) }, +#ifdef CONFIG_ACS + { INT_RANGE(acs, 0, 1) }, +#endif /* CONFIG_ACS */ #ifdef CONFIG_MESH { FUNC(mesh_basic_rates) }, { INT(dot11MeshMaxRetries) }, @@ -1918,6 +2005,7 @@ static const struct parse_data ssid_fields[] = { { INT(dot11MeshHoldingTimeout) }, #endif /* CONFIG_MESH */ { INT(wpa_ptk_rekey) }, + { INT(group_rekey) }, { STR(bgscan) }, { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, #ifdef CONFIG_P2P @@ -1967,6 +2055,8 @@ static const struct parse_data ssid_fields[] = { { INT(update_identifier) }, #endif /* CONFIG_HS20 */ { INT_RANGE(mac_addr, 0, 2) }, + { INT_RANGE(pbss, 0, 2) }, + { INT_RANGE(wps_disabled, 0, 1) }, }; #undef OFFSET @@ -2271,6 +2361,11 @@ void wpa_config_free(struct wpa_config *config) os_free(config->bgscan); os_free(config->wowlan_triggers); os_free(config->fst_group_id); + os_free(config->sched_scan_plans); +#ifdef CONFIG_MBO + os_free(config->non_pref_chan); +#endif /* CONFIG_MBO */ + os_free(config); } @@ -2453,7 +2548,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) * @var: Variable name, e.g., "ssid" * @value: Variable value * @line: Line number in configuration file or 0 if not used - * Returns: 0 on success, -1 on failure + * Returns: 0 on success with possible change in the value, 1 on success with + * no change to previously configured value, or -1 on failure * * This function can be used to set network configuration variables based on * both the configuration file and management interface input. The value @@ -2474,7 +2570,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, if (os_strcmp(var, field->name) != 0) continue; - if (field->parser(field, ssid, line, value)) { + ret = field->parser(field, ssid, line, value); + if (ret < 0) { if (line) { wpa_printf(MSG_ERROR, "Line %d: failed to " "parse %s '%s'.", line, var, value); @@ -2573,9 +2670,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) return props; err: - value = *props; - while (value) - os_free(value++); + for (i = 0; props[i]; i++) + os_free(props[i]); os_free(props); return NULL; #endif /* NO_CONFIG_WRITE */ @@ -2604,8 +2700,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var) for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; - if (os_strcmp(var, field->name) == 0) - return field->writer(field, ssid); + if (os_strcmp(var, field->name) == 0) { + char *ret = field->writer(field, ssid); + + if (ret && has_newline(ret)) { + wpa_printf(MSG_ERROR, + "Found newline in value for %s; not returning it", + var); + os_free(ret); + ret = NULL; + } + + return ret; + } } return NULL; @@ -2790,6 +2897,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, if (os_strcmp(var, "password") == 0 && os_strncmp(value, "ext:", 4) == 0) { + if (has_newline(value)) + return -1; str_clear_free(cred->password); cred->password = os_strdup(value); cred->ext_password = 1; @@ -2840,9 +2949,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, } val = wpa_config_parse_string(value, &len); - if (val == NULL) { + if (val == NULL || + (os_strcmp(var, "excluded_ssid") != 0 && + os_strcmp(var, "roaming_consortium") != 0 && + os_strcmp(var, "required_roaming_consortium") != 0 && + has_newline(val))) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " "value '%s'.", line, var, value); + os_free(val); return -1; } @@ -3540,6 +3654,11 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; config->cert_in_cb = DEFAULT_CERT_IN_CB; + config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION; + +#ifdef CONFIG_MBO + config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA; +#endif /* CONFIG_MBO */ if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); @@ -3646,6 +3765,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data, return -1; } + if (has_newline(pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline", + line, data->name); + return -1; + } + tmp = os_strdup(pos); if (tmp == NULL) return -1; @@ -3684,22 +3809,12 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { - size_t len; struct wpabuf **dst, *tmp; - len = os_strlen(pos); - if (len & 0x01) - return -1; - - tmp = wpabuf_alloc(len / 2); - if (tmp == NULL) + tmp = wpabuf_parse_bin(pos); + if (!tmp) return -1; - if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) { - wpabuf_free(tmp); - return -1; - } - dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); wpabuf_free(*dst); *dst = tmp; @@ -4246,6 +4361,16 @@ 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(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(gas_address3), 0 }, + { INT_RANGE(ftm_responder, 0, 1), 0 }, + { INT_RANGE(ftm_initiator, 0, 1), 0 }, }; #undef FUNC @@ -4304,6 +4429,23 @@ int wpa_config_get_value(const char *name, struct wpa_config *config, } +int wpa_config_get_num_global_field_names(void) +{ + return NUM_GLOBAL_FIELDS; +} + + +const char * wpa_config_get_global_field_name(unsigned int i, int *no_var) +{ + if (i >= NUM_GLOBAL_FIELDS) + return NULL; + + if (no_var) + *no_var = !global_fields[i].param1; + return global_fields[i].name; +} + + int wpa_config_process_global(struct wpa_config *config, char *pos, int line) { size_t i; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 627f38b..48e64be 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -39,6 +39,8 @@ #define DEFAULT_KEY_MGMT_OFFLOAD 1 #define DEFAULT_CERT_IN_CB 1 #define DEFAULT_P2P_GO_CTWINDOW 0 +#define DEFAULT_WPA_RSC_RELAXATION 1 +#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED #include "config_ssid.h" #include "wps/wps.h" @@ -331,6 +333,7 @@ struct wpa_cred { #define CFG_CHANGED_EXT_PW_BACKEND BIT(14) #define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15) #define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16) +#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17) /** * struct wpa_config - wpa_supplicant configuration data @@ -761,12 +764,17 @@ struct wpa_config { * frequency list of the local device and the peer device. * * @P2P_GO_FREQ_MOVE_STAY: Prefer to stay on the current frequency. + * + * @P2P_GO_FREQ_MOVE_SCM_ECSA: Same as + * P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS but a transition is possible only + * if all the group members advertise eCSA support. */ enum { P2P_GO_FREQ_MOVE_SCM = 0, P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS = 1, P2P_GO_FREQ_MOVE_STAY = 2, - P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_STAY, + P2P_GO_FREQ_MOVE_SCM_ECSA = 3, + P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_SCM_ECSA, } p2p_go_freq_change_policy; #define DEFAULT_P2P_GO_FREQ_MOVE P2P_GO_FREQ_MOVE_STAY @@ -1031,7 +1039,8 @@ struct wpa_config { * * By default, PMF is disabled unless enabled by the per-network * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change - * this default behavior. + * this default behavior for RSN network (this is not applicable for + * non-RSN cases). */ enum mfp_options pmf; @@ -1247,6 +1256,78 @@ struct wpa_config { * interface. */ int fst_llt; + + /** + * wpa_rsc_relaxation - RSC relaxation on GTK installation + * + * Values: + * 0 - use the EAPOL-Key RSC value on GTK installation + * 1 - use the null RSC if a bogus RSC value is detected in message 3 + * of 4-Way Handshake or message 1 of Group Key Handshake. + */ + int wpa_rsc_relaxation; + + /** + * sched_scan_plans - Scan plans for scheduled scan + * + * Each scan plan specifies the interval between scans and the number of + * iterations. The last scan plan only specifies the scan interval and + * will be run infinitely. + * + * format: <interval:iterations> <interval2:iterations2> ... <interval> + */ + char *sched_scan_plans; + +#ifdef CONFIG_MBO + /** + * non_pref_chan - Non-preferred channels list, separated by spaces. + * + * format: op_class:chan:preference:reason<:detail> + * Detail is optional. + */ + char *non_pref_chan; + + /** + * mbo_cell_capa - Cellular capabilities for MBO + */ + enum mbo_cellular_capa mbo_cell_capa; +#endif /* CONFIG_MBO */ + + /** + * gas_address3 - GAS Address3 field behavior + * + * Values: + * 0 - P2P specification (Address3 = AP BSSID) + * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when + * sent to not-associated AP; if associated, AP BSSID) + */ + int gas_address3; + + /** + * ftm_responder - Publish FTM (fine timing measurement) + * responder functionality + * + * Values: + * 0 - do not publish FTM responder functionality (Default) + * 1 - publish FTM responder functionality in + * bit 70 of Extended Capabilities element + * Note, actual FTM responder operation is managed outside + * wpa_supplicant. + */ + int ftm_responder; + + /** + * ftm_initiator - Publish FTM (fine timing measurement) + * initiator functionality + * + * Values: + * 0 - do not publish FTM initiator functionality (Default) + * 1 - publish FTM initiator functionality in + * bit 71 of Extended Capabilities element + * Note, actual FTM initiator operation is managed outside + * wpa_supplicant. + */ + int ftm_initiator; }; @@ -1305,6 +1386,9 @@ void wpa_config_debug_dump_networks(struct wpa_config *config); /* Prototypes for common functions from config.c */ int wpa_config_process_global(struct wpa_config *config, char *pos, int line); +int wpa_config_get_num_global_field_names(void); + +const char * wpa_config_get_global_field_name(unsigned int i, int *no_var); /* Prototypes for backend specific functions from the selected config_*.c */ diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index fb438ea..7ae1654 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -747,10 +747,16 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(no_auto_peer); INT(frequency); INT(fixed_freq); +#ifdef CONFIG_ACS + INT(acs); +#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(pbss); + INT(wps_disabled); #ifdef CONFIG_IEEE80211W write_int(f, "ieee80211w", ssid->ieee80211w, MGMT_FRAME_PROTECTION_DEFAULT); @@ -779,6 +785,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT); #endif /* CONFIG_MESH */ INT(wpa_ptk_rekey); + INT(group_rekey); INT(ignore_broadcast_ssid); #ifdef CONFIG_HT_OVERRIDES INT_DEF(disable_ht, DEFAULT_DISABLE_HT); @@ -1136,6 +1143,22 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE) fprintf(f, "p2p_go_freq_change_policy=%u\n", config->p2p_go_freq_change_policy); + if (WPA_GET_BE32(config->ip_addr_go)) + fprintf(f, "ip_addr_go=%u.%u.%u.%u\n", + config->ip_addr_go[0], config->ip_addr_go[1], + config->ip_addr_go[2], config->ip_addr_go[3]); + if (WPA_GET_BE32(config->ip_addr_mask)) + fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n", + config->ip_addr_mask[0], config->ip_addr_mask[1], + config->ip_addr_mask[2], config->ip_addr_mask[3]); + if (WPA_GET_BE32(config->ip_addr_start)) + fprintf(f, "ip_addr_start=%u.%u.%u.%u\n", + config->ip_addr_start[0], config->ip_addr_start[1], + config->ip_addr_start[2], config->ip_addr_start[3]); + if (WPA_GET_BE32(config->ip_addr_end)) + fprintf(f, "ip_addr_end=%u.%u.%u.%u\n", + config->ip_addr_end[0], config->ip_addr_end[1], + config->ip_addr_end[2], config->ip_addr_end[3]); #endif /* CONFIG_P2P */ if (config->country[0] && config->country[1]) { fprintf(f, "country=%c%c\n", @@ -1299,6 +1322,28 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->wps_priority) fprintf(f, "wps_priority=%d\n", config->wps_priority); + + if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION) + fprintf(f, "wpa_rsc_relaxation=%d\n", + config->wpa_rsc_relaxation); + + if (config->sched_scan_plans) + fprintf(f, "sched_scan_plans=%s\n", config->sched_scan_plans); + +#ifdef CONFIG_MBO + if (config->non_pref_chan) + 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); +#endif /* CONFIG_MBO */ + + if (config->gas_address3) + fprintf(f, "gas_address3=%d\n", config->gas_address3); + + if (config->ftm_responder) + fprintf(f, "ftm_responder=%d\n", config->ftm_responder); + if (config->ftm_initiator) + fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 7ef326c..010b594 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -360,6 +360,19 @@ struct wpa_ssid { } mode; /** + * pbss - Whether to use PBSS. Relevant to DMG networks only. + * 0 = do not use PBSS + * 1 = use PBSS + * 2 = don't care (not allowed in AP mode) + * Used together with mode configuration. When mode is AP, it + * means to start a PCP instead of a regular AP. When mode is INFRA it + * means connect to a PCP instead of AP. In this mode you can also + * specify 2 (don't care) meaning connect to either AP or PCP. + * P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in DMG network. + */ + int pbss; + + /** * disabled - Whether this network is currently disabled * * 0 = this network can be used (default). @@ -431,6 +444,18 @@ struct wpa_ssid { */ int fixed_freq; +#ifdef CONFIG_ACS + /** + * ACS - Automatic Channel Selection for AP mode + * + * If present, it will be handled together with frequency. + * frequency will be used to determine hardware mode only, when it is + * used for both hardware mode and channel when used alone. This will + * force the channel to be set to 0, thus enabling ACS. + */ + int acs; +#endif /* CONFIG_ACS */ + /** * mesh_basic_rates - BSS Basic rate set for mesh network * @@ -449,6 +474,10 @@ struct wpa_ssid { int vht; + u8 max_oper_chwidth; + + unsigned int vht_center_freq2; + /** * wpa_ptk_rekey - Maximum lifetime for PTK in seconds * @@ -458,6 +487,14 @@ struct wpa_ssid { int wpa_ptk_rekey; /** + * 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. + */ + int group_rekey; + + /** * scan_freq - Array of frequencies to scan or %NULL for all * * This is an optional zero-terminated array of frequencies in @@ -719,6 +756,14 @@ struct wpa_ssid { * this MBSS will trigger a peering attempt. */ int no_auto_peer; + + /** + * wps_disabled - WPS disabled in AP mode + * + * 0 = WPS enabled and configured (default) + * 1 = WPS disabled + */ + int wps_disabled; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index 199f04f..82ba3b0 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -933,6 +933,7 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) #ifdef CONFIG_HS20 INT(update_identifier); #endif /* CONFIG_HS20 */ + INT(group_rekey); #undef STR #undef INT diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 3b97806..d814fdf 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -15,6 +15,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/uuid.h" +#include "utils/module_tests.h" #include "common/version.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -55,6 +56,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + const char *input, char *buf, int len); static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val); @@ -310,6 +312,33 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band) } +static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *lci; + + if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) { + wpabuf_free(wpa_s->lci); + wpa_s->lci = NULL; + return 0; + } + + lci = wpabuf_parse_bin(cmd); + if (!lci) + return -1; + + if (os_get_reltime(&wpa_s->lci_time)) { + wpabuf_free(lci); + return -1; + } + + wpabuf_free(wpa_s->lci); + wpa_s->lci = lci; + + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -371,6 +400,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wps_corrupt_pkhash = atoi(value); wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", wps_corrupt_pkhash); + } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) { + if (value[0] == '\0') { + wps_force_auth_types_in_use = 0; + } else { + wps_force_auth_types = strtol(value, NULL, 0); + wps_force_auth_types_in_use = 1; + } + } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) { + if (value[0] == '\0') { + wps_force_encr_types_in_use = 0; + } else { + wps_force_encr_types = strtol(value, NULL, 0); + wps_force_encr_types_in_use = 1; + } #endif /* CONFIG_WPS_TESTING */ } else if (os_strcasecmp(cmd, "ampdu") == 0) { if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) @@ -378,7 +421,6 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { - extern unsigned int tdls_testing; tdls_testing = strtol(value, NULL, 0); wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); #endif /* CONFIG_TDLS_TESTING */ @@ -467,6 +509,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->extra_roc_dur = atoi(value); } else if (os_strcasecmp(cmd, "test_failure") == 0) { wpa_s->test_failure = atoi(value); + } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) { + wpa_s->p2p_go_csa_on_inv = !!atoi(value); + } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) { + wpa_s->ignore_auth_resp = !!atoi(value); + } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) { + wpa_s->ignore_assoc_disallow = !!atoi(value); + } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) { + wpa_s->reject_btm_req_reason = atoi(value); #endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_NO_CONFIG_BLOBS } else if (os_strcmp(cmd, "blob") == 0) { @@ -474,6 +524,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_CONFIG_BLOBS */ } else if (os_strcasecmp(cmd, "setband") == 0) { ret = wpas_ctrl_set_band(wpa_s, value); +#ifdef CONFIG_MBO + } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) { + ret = wpas_mbo_update_non_pref_chan(wpa_s, value); + } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { + wpas_mbo_update_cell_capa(wpa_s, atoi(value)); +#endif /* CONFIG_MBO */ + } else if (os_strcasecmp(cmd, "lci") == 0) { + ret = wpas_ctrl_iface_set_lci(wpa_s, value); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -940,7 +998,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, if (os_strcmp(cmd, "any") == 0) _bssid = NULL; else if (os_strcmp(cmd, "get") == 0) { - ret = wps_generate_pin(); + if (wps_generate_pin((unsigned int *) &ret) < 0) + return -1; goto done; } else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", @@ -1833,6 +1892,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, "mode=P2P GO - group " "formation\n"); break; + case WPAS_MODE_MESH: + ret = os_snprintf(pos, end - pos, + "mode=mesh\n"); + break; default: ret = 0; break; @@ -2703,6 +2766,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove( return 0; } + +static int wpa_supplicant_ctrl_iface_mesh_peer_remove( + struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + + if (hwaddr_aton(cmd, addr) < 0) + return -1; + + return wpas_mesh_peer_remove(wpa_s, addr); +} + + +static int wpa_supplicant_ctrl_iface_mesh_peer_add( + struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + int duration; + char *pos; + + pos = os_strstr(cmd, " duration="); + if (pos) { + *pos = '\0'; + duration = atoi(pos + 10); + } else { + duration = -1; + } + + if (hwaddr_aton(cmd, addr)) + return -1; + + return wpas_mesh_peer_add(wpa_s, addr, duration); +} + #endif /* CONFIG_MESH */ @@ -2832,15 +2929,10 @@ static int wpa_supplicant_ctrl_iface_add_network( wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); - ssid = wpa_config_add_network(wpa_s->conf); + ssid = wpa_supplicant_add_network(wpa_s); if (ssid == NULL) return -1; - wpas_notify_network_added(wpa_s, ssid); - - ssid->disabled = 1; - wpa_config_set_network_defaults(ssid); - ret = os_snprintf(buf, buflen, "%d\n", ssid->id); if (os_snprintf_error(buflen, ret)) return -1; @@ -2853,7 +2945,7 @@ static int wpa_supplicant_ctrl_iface_remove_network( { int id; struct wpa_ssid *ssid; - int was_disabled; + int result; /* cmd: "<network id>" or "all" */ if (os_strcmp(cmd, "all") == 0) { @@ -2889,54 +2981,17 @@ static int wpa_supplicant_ctrl_iface_remove_network( id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); - ssid = wpa_config_get_network(wpa_s->conf, id); - if (ssid) - wpas_notify_network_removed(wpa_s, ssid); - if (ssid == NULL) { + result = wpa_supplicant_remove_network(wpa_s, id); + if (result == -1) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " "id=%d", id); return -1; } - - if (wpa_s->last_ssid == ssid) - wpa_s->last_ssid = NULL; - - if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) { -#ifdef CONFIG_SME - wpa_s->sme.prev_bssid_set = 0; -#endif /* CONFIG_SME */ - /* - * Invalidate the EAP session cache if the current or - * previously used network is removed. - */ - eapol_sm_invalidate_cached_session(wpa_s->eapol); - } - - if (ssid == wpa_s->current_ssid) { - wpa_sm_set_config(wpa_s->wpa, NULL); - eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); - - if (wpa_s->wpa_state >= WPA_AUTHENTICATING) - wpa_s->own_disconnect_req = 1; - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - } - - was_disabled = ssid->disabled; - - if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + if (result == -2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the " "network id=%d", id); return -1; } - - if (!was_disabled && wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove " - "network from filters"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); - } - return 0; } @@ -2945,22 +3000,29 @@ static int wpa_supplicant_ctrl_iface_update_network( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, char *name, char *value) { - if (wpa_config_set(ssid, name, value, 0) < 0) { + int ret; + + ret = wpa_config_set(ssid, name, value, 0); + if (ret < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " "variable '%s'", name); return -1; } + if (ret == 1) + return 0; /* No change to the previously configured value */ if (os_strcmp(name, "bssid") != 0 && - os_strcmp(name, "priority") != 0) + os_strcmp(name, "priority") != 0) { wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); - if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) { - /* - * Invalidate the EAP session cache if anything in the current - * or previously used configuration changes. - */ - eapol_sm_invalidate_cached_session(wpa_s->eapol); + if (wpa_s->current_ssid == ssid || + wpa_s->current_ssid == NULL) { + /* + * Invalidate the EAP session cache if anything in the + * current or previously used configuration changes. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } } if ((os_strcmp(name, "psk") == 0 && @@ -3935,6 +3997,15 @@ static int wpa_supplicant_ctrl_iface_get_capability( } #endif /* CONFIG_FIPS */ +#ifdef CONFIG_ACS + if (os_strcmp(field, "acs") == 0) { + res = os_snprintf(buf, buflen, "ACS"); + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } +#endif /* CONFIG_ACS */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", field); @@ -4195,9 +4266,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (mask & WPA_BSS_MASK_P2P_SCAN) { ie = (const u8 *) (bss + 1); ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); - if (ret < 0 || ret >= end - pos) + if (ret >= end - pos) return 0; - pos += ret; + if (ret > 0) + pos += ret; } #endif /* CONFIG_P2P */ @@ -4231,6 +4303,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, #ifdef CONFIG_INTERWORKING if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { struct wpa_bss_anqp *anqp = bss->anqp; + struct wpa_bss_anqp_elem *elem; + pos = anqp_add_hex(pos, end, "anqp_capability_list", anqp->capability_list); pos = anqp_add_hex(pos, end, "anqp_venue_name", @@ -4260,6 +4334,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", anqp->hs20_osu_providers_list); #endif /* CONFIG_HS20 */ + + dl_list_for_each(elem, &anqp->anqp_elems, + struct wpa_bss_anqp_elem, list) { + char title[20]; + + os_snprintf(title, sizeof(title), "anqp[%u]", + elem->infoid); + pos = anqp_add_hex(pos, end, title, elem->payload); + } } #endif /* CONFIG_INTERWORKING */ @@ -4267,9 +4350,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (mask & WPA_BSS_MASK_MESH_SCAN) { ie = (const u8 *) (bss + 1); ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end); - if (ret < 0 || ret >= end - pos) + if (ret >= end - pos) return 0; - pos += ret; + if (ret > 0) + pos += ret; } #endif /* CONFIG_MESH */ @@ -4676,7 +4760,7 @@ static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt) return -1; } - if (isblank(*last)) { + if (isblank((unsigned char) *last)) { i++; break; } @@ -4848,6 +4932,30 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd) } +static int parse_freq(int chwidth, int freq2) +{ + if (freq2 < 0) + return -1; + if (freq2) + return VHT_CHANWIDTH_80P80MHZ; + + switch (chwidth) { + case 0: + case 20: + case 40: + return VHT_CHANWIDTH_USE_HT; + case 80: + return VHT_CHANWIDTH_80MHZ; + case 160: + return VHT_CHANWIDTH_160MHZ; + default: + wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", + chwidth); + return -1; + } +} + + static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -4864,7 +4972,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, int go_intent = -1; int freq = 0; int pd; - int ht40, vht; + 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; if (!wpa_s->global->p2p_init_wpa_s) return -1; @@ -4877,7 +4987,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] */ + * [ht40] [vht] [auto] [ssid=<hexdump>] */ if (hwaddr_aton(cmd, addr)) return -1; @@ -4925,11 +5035,41 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, return -1; } + pos2 = os_strstr(pos, " freq2="); + if (pos2) + freq2 = atoi(pos2 + 7); + + pos2 = os_strstr(pos, " max_oper_chwidth="); + if (pos2) + chwidth = atoi(pos2 + 18); + + max_oper_chwidth = parse_freq(chwidth, freq2); + if (max_oper_chwidth < 0) + return -1; + + pos2 = os_strstr(pos, " ssid="); + if (pos2) { + char *end; + + pos2 += 6; + end = os_strchr(pos2, ' '); + if (!end) + group_ssid_len = os_strlen(pos2) / 2; + else + group_ssid_len = (end - pos2) / 2; + if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN || + hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0) + return -1; + group_ssid = _group_ssid; + } + if (os_strncmp(pos, "pin", 3) == 0) { /* Request random PIN (to be displayed) and enable the PIN */ wps_method = WPS_PIN_DISPLAY; } else if (os_strncmp(pos, "pbc", 3) == 0) { wps_method = WPS_PBC; + } else if (os_strstr(pos, "p2ps") != NULL) { + wps_method = WPS_P2PS; } else { pin = pos; pos = os_strchr(pin, ' '); @@ -4938,8 +5078,6 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, *pos++ = '\0'; if (os_strncmp(pos, "display", 7) == 0) wps_method = WPS_PIN_DISPLAY; - else if (os_strncmp(pos, "p2ps", 4) == 0) - wps_method = WPS_P2PS; } if (!wps_pin_str_valid(pin)) { os_memcpy(buf, "FAIL-INVALID-PIN\n", 17); @@ -4949,8 +5087,9 @@ 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, persistent_id, pd, - ht40, vht); + auth, go_intent, freq, freq2, persistent_id, + pd, ht40, vht, max_oper_chwidth, + group_ssid, group_ssid_len); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; @@ -5505,7 +5644,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; + int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; id = atoi(cmd); pos = os_strstr(cmd, " peer="); @@ -5543,8 +5682,20 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; - return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht, - pref_freq); + pos = os_strstr(cmd, "freq2="); + if (pos) + freq2 = atoi(pos + 6); + + pos = os_strstr(cmd, " max_oper_chwidth="); + if (pos) + chwidth = atoi(pos + 18); + + max_oper_chwidth = parse_freq(chwidth, freq2); + if (max_oper_chwidth < 0) + return -1; + + return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, + max_oper_chwidth, pref_freq); } @@ -5591,7 +5742,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 ht40, int vht) + int id, int freq, int vht_center_freq2, + int ht40, int vht, int vht_chwidth) { struct wpa_ssid *ssid; @@ -5603,8 +5755,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return -1; } - return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht, - NULL, 0, 0); + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, + vht_center_freq2, 0, ht40, vht, + vht_chwidth, NULL, 0, 0); } @@ -5613,11 +5766,14 @@ 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 max_oper_chwidth, chwidth = 0, freq2 = 0; char *token, *context = NULL; while ((token = str_token(cmd, " ", &context))) { if (sscanf(token, "freq=%d", &freq) == 1 || - sscanf(token, "persistent=%d", &group_id) == 1) { + sscanf(token, "freq2=%d", &freq2) == 1 || + sscanf(token, "persistent=%d", &group_id) == 1 || + sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) { continue; } else if (os_strcmp(token, "ht40") == 0) { ht40 = 1; @@ -5634,11 +5790,40 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) } } + max_oper_chwidth = parse_freq(chwidth, freq2); + if (max_oper_chwidth < 0) + return -1; + if (group_id >= 0) return p2p_ctrl_group_add_persistent(wpa_s, group_id, - freq, ht40, vht); + freq, freq2, ht40, vht, + max_oper_chwidth); + + return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, + max_oper_chwidth); +} + + +static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd, + char *buf, size_t buflen) +{ + u8 dev_addr[ETH_ALEN]; + struct wpa_ssid *ssid; + int res; + const u8 *iaddr; + + ssid = wpa_s->current_ssid; + if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO || + hwaddr_aton(cmd, dev_addr)) + return -1; - return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht); + iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr); + if (!iaddr) + return -1; + res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr)); + if (os_snprintf_error(buflen, res)) + return -1; + return res; } @@ -5797,8 +5982,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) } if (os_strcmp(cmd, "listen_channel") == 0) { - return p2p_set_listen_channel(wpa_s->global->p2p, 81, - atoi(param), 1); + char *pos; + u8 channel, op_class; + + channel = atoi(param); + pos = os_strchr(param, ' '); + op_class = pos ? atoi(pos) : 81; + + return p2p_set_listen_channel(wpa_s->global->p2p, op_class, + channel, 1); } if (os_strcmp(cmd, "ssid_postfix") == 0) { @@ -6059,6 +6251,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) return 0; } + +static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd) +{ + int freq = 0, period = 0, interval = 0, count = 0; + + if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4) + { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid P2P LO Start parameter: '%s'", cmd); + return -1; + } + + return wpas_p2p_lo_start(wpa_s, freq, period, interval, count); +} + #endif /* CONFIG_P2P */ @@ -6176,6 +6383,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; used = hwaddr_aton2(dst, dst_addr); if (used < 0) @@ -6193,6 +6401,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) #else /* CONFIG_HS20 */ return -1; #endif /* CONFIG_HS20 */ + } else if (os_strncmp(pos, "mbo:", 4) == 0) { +#ifdef CONFIG_MBO + int num = atoi(pos + 4); + if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF) + return -1; + get_cell_pref = 1; +#else /* CONFIG_MBO */ + return -1; +#endif /* CONFIG_MBO */ } else { id[num_id] = atoi(pos); if (id[num_id]) @@ -6207,7 +6424,8 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) if (num_id == 0) return -1; - return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes); + return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes, + get_cell_pref); } @@ -6378,7 +6596,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst) if (subtypes == 0) return -1; - return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0); + return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0); } @@ -6401,7 +6619,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s, ret = hs20_anqp_send_req(wpa_s, addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), - buf, len); + buf, len, 0); os_free(buf); @@ -6447,14 +6665,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s, ret = hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), - buf, len); + buf, len, 0); os_free(buf); return ret; } -static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) +static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply, + int buflen) +{ + u8 dst_addr[ETH_ALEN]; + int used; + char *ctx = NULL, *icon, *poffset, *psize; + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + cmd += used; + + icon = str_token(cmd, " ", &ctx); + poffset = str_token(cmd, " ", &ctx); + psize = str_token(cmd, " ", &ctx); + if (!icon || !poffset || !psize) + return -1; + + wpa_s->fetch_osu_icon_in_progress = 0; + return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize), + reply, buflen); +} + + +static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 dst_addr[ETH_ALEN]; + int used; + char *icon; + + if (!cmd[0]) + return hs20_del_icon(wpa_s, NULL, NULL); + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + + while (cmd[used] == ' ') + used++; + icon = cmd[used] ? &cmd[used] : NULL; + + return hs20_del_icon(wpa_s, dst_addr, icon); +} + + +static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem) { u8 dst_addr[ETH_ALEN]; int used; @@ -6470,7 +6733,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) wpa_s->fetch_osu_icon_in_progress = 0; return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST), - (u8 *) icon, os_strlen(icon)); + (u8 *) icon, os_strlen(icon), inmem); } #endif /* CONFIG_HS20 */ @@ -6560,14 +6823,27 @@ 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; + int query_reason, list = 0; query_reason = atoi(cmd); - wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d", - query_reason); + cmd = os_strchr(cmd, ' '); + if (cmd) { + cmd++; + if (os_strncmp(cmd, "list", 4) == 0) { + list = 1; + } else { + wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s", + cmd); + return -1; + } + } - return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason); + 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); } #endif /* CONFIG_WNM */ @@ -6632,6 +6908,28 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, } +static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + const char *pos; + int threshold = 0; + int hysteresis = 0; + + if (wpa_s->bgscan && wpa_s->bgscan_priv) { + wpa_printf(MSG_DEBUG, + "Reject SIGNAL_MONITOR command - bgscan is active"); + return -1; + } + pos = os_strstr(cmd, "THRESHOLD="); + if (pos) + threshold = atoi(pos + 10); + pos = os_strstr(cmd, "HYSTERESIS="); + if (pos) + hysteresis = atoi(pos + 11); + return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis); +} + + static int wpas_ctrl_iface_get_pref_freq_list( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -6679,6 +6977,34 @@ static int wpas_ctrl_iface_get_pref_freq_list( } +static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + int ret, i; + char *pos, *end; + + ret = os_snprintf(buf, buflen, "%016llX:\n", + (long long unsigned) wpa_s->drv_flags); + if (os_snprintf_error(buflen, ret)) + return -1; + + pos = buf + ret; + end = buf + buflen; + + for (i = 0; i < 64; i++) { + if (wpa_s->drv_flags & (1LLU << i)) { + ret = os_snprintf(pos, end - pos, "%s\n", + driver_flag_to_string(1LLU << i)); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + } + + return pos - buf; +} + + static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { @@ -6736,13 +7062,13 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ vendor_id = strtoul(cmd, &pos, 16); - if (!isblank(*pos)) + if (!isblank((unsigned char) *pos)) return -EINVAL; subcmd = strtoul(pos, &pos, 10); if (*pos != '\0') { - if (!isblank(*pos++)) + if (!isblank((unsigned char) *pos++)) return -EINVAL; data_len = os_strlen(pos); } @@ -6790,10 +7116,20 @@ 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 (wpa_s->wpa_state >= WPA_AUTHENTICATING) { + /* + * Avoid possible auto connect re-connection on getting + * disconnected due to state flush. + */ + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + } + #ifdef CONFIG_P2P + wpas_p2p_group_remove(p2p_wpa_s, "*"); wpas_p2p_cancel(p2p_wpa_s); p2p_ctrl_flush(p2p_wpa_s); - wpas_p2p_group_remove(p2p_wpa_s, "*"); wpas_p2p_service_flush(p2p_wpa_s); p2p_wpa_s->global->p2p_disabled = 0; p2p_wpa_s->global->p2p_per_sta_psk = 0; @@ -6803,12 +7139,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL; p2p_wpa_s->global->p2p_go_avoid_freq.num = 0; p2p_wpa_s->global->pending_p2ps_group = 0; + p2p_wpa_s->global->pending_p2ps_group_freq = 0; #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS_TESTING wps_version_number = 0x20; wps_testing_dummy_cred = 0; wps_corrupt_pkhash = 0; + wps_force_auth_types_in_use = 0; + wps_force_encr_types_in_use = 0; #endif /* CONFIG_WPS_TESTING */ #ifdef CONFIG_WPS wpa_s->wps_fragment_size = 0; @@ -6820,7 +7159,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING - extern unsigned int tdls_testing; tdls_testing = 0; #endif /* CONFIG_TDLS_TESTING */ wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); @@ -6866,7 +7204,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->next_ssid = NULL; #ifdef CONFIG_INTERWORKING +#ifdef CONFIG_HS20 hs20_cancel_fetch_osu(wpa_s); + hs20_del_icon(wpa_s, NULL, NULL); +#endif /* CONFIG_HS20 */ #endif /* CONFIG_INTERWORKING */ wpa_s->ext_mgmt_frame_handling = 0; @@ -6874,6 +7215,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_TESTING_OPTIONS wpa_s->extra_roc_dur = 0; wpa_s->test_failure = WPAS_TEST_FAILURE_NONE; + wpa_s->p2p_go_csa_on_inv = 0; + wpa_s->ignore_auth_resp = 0; + wpa_s->ignore_assoc_disallow = 0; + wpa_s->reject_btm_req_reason = 0; + wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); #endif /* CONFIG_TESTING_OPTIONS */ wpa_s->disconnected = 0; @@ -6891,6 +7237,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) } eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); + wpa_s->wnmsleep_used = 0; + +#ifdef CONFIG_SME + wpa_s->sme.last_unprot_disconnect.sec = 0; +#endif /* CONFIG_SME */ } @@ -6947,6 +7298,13 @@ static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); + /* + * work->type points to a buffer in ework, so need to replace + * that here with a fixed string to avoid use of freed memory + * in debug prints. + */ + work->type = "freed-ext-work"; + work->ctx = NULL; os_free(ework); return; } @@ -7396,6 +7754,76 @@ static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s) } +static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *pos, *param; + size_t len; + u8 *buf; + int freq = 0, datarate = 0, ssi_signal = 0; + union wpa_event_data event; + + if (!wpa_s->ext_mgmt_frame_handling) + return -1; + + /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */ + + wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd); + + pos = cmd; + param = os_strstr(pos, "freq="); + if (param) { + param += 5; + freq = atoi(param); + } + + param = os_strstr(pos, " datarate="); + if (param) { + param += 10; + datarate = atoi(param); + } + + param = os_strstr(pos, " ssi_signal="); + if (param) { + param += 12; + ssi_signal = atoi(param); + } + + param = os_strstr(pos, " frame="); + if (param == NULL) + return -1; + param += 7; + + len = os_strlen(param); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(param, buf, len) < 0) { + os_free(buf); + return -1; + } + + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.freq = freq; + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.ssi_signal = ssi_signal; + event.rx_mgmt.datarate = datarate; + wpa_s->ext_mgmt_frame_handling = 0; + wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event); + wpa_s->ext_mgmt_frame_handling = 1; + + os_free(buf); + + return 0; +} + + static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; @@ -7495,7 +7923,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len) #define HWSIM_PACKETLEN 1500 #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header)) -void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) +static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) { struct wpa_supplicant *wpa_s = ctx; const struct ether_header *eth; @@ -7529,6 +7958,8 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, char *cmd) { int enabled = atoi(cmd); + char *pos; + const char *ifname; if (!enabled) { if (wpa_s->l2_test) { @@ -7542,7 +7973,13 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, if (wpa_s->l2_test) return 0; - wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, + pos = os_strstr(cmd, " ifname="); + if (pos) + ifname = pos + 8; + else + ifname = wpa_s->ifname; + + wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr, ETHERTYPE_IP, wpas_data_test_rx, wpa_s, 1); if (wpa_s->l2_test == NULL) @@ -7663,8 +8100,6 @@ done: static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_fail_func[256]; - extern unsigned int wpa_trace_fail_after; char *pos; wpa_trace_fail_after = atoi(cmd); @@ -7687,9 +8122,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_fail_func[256]; - extern unsigned int wpa_trace_fail_after; - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, wpa_trace_fail_func); #else /* WPA_TRACE_BFD */ @@ -7701,8 +8133,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_test_fail_func[256]; - extern unsigned int wpa_trace_test_fail_after; char *pos; wpa_trace_test_fail_after = atoi(cmd); @@ -7725,9 +8155,6 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_test_fail_func[256]; - extern unsigned int wpa_trace_test_fail_after; - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, wpa_trace_test_fail_func); #else /* WPA_TRACE_BFD */ @@ -7735,62 +8162,64 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, #endif /* WPA_TRACE_BFD */ } -#endif /* CONFIG_TESTING_OPTIONS */ - -static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s) +static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx) { - unsigned int i; - char buf[30]; + struct wpa_supplicant *wpa_s = eloop_ctx; + int i, count = (intptr_t) timeout_ctx; - wpa_printf(MSG_DEBUG, "Update vendor elements"); + wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages", + count); + for (i = 0; i < count; i++) { + wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d", + i + 1, count); + } +} - for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { - if (wpa_s->vendor_elem[i]) { - int res; - res = os_snprintf(buf, sizeof(buf), "frame[%u]", i); - if (!os_snprintf_error(sizeof(buf), res)) { - wpa_hexdump_buf(MSG_DEBUG, buf, - wpa_s->vendor_elem[i]); - } - } - } +static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int count; -#ifdef CONFIG_P2P - if (wpa_s->parent == wpa_s && - wpa_s->global->p2p && - !wpa_s->global->p2p_disabled) - p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); -#endif /* CONFIG_P2P */ + count = atoi(cmd); + if (count <= 0) + return -1; + + return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s, + (void *) (intptr_t) count); } -static struct wpa_supplicant * -wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s, - enum wpa_vendor_elem_frame frame) +static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, + const char *cmd) { - switch (frame) { -#ifdef CONFIG_P2P - case VENDOR_ELEM_PROBE_REQ_P2P: - case VENDOR_ELEM_PROBE_RESP_P2P: - case VENDOR_ELEM_PROBE_RESP_P2P_GO: - case VENDOR_ELEM_BEACON_P2P_GO: - case VENDOR_ELEM_P2P_PD_REQ: - case VENDOR_ELEM_P2P_PD_RESP: - case VENDOR_ELEM_P2P_GO_NEG_REQ: - case VENDOR_ELEM_P2P_GO_NEG_RESP: - case VENDOR_ELEM_P2P_GO_NEG_CONF: - case VENDOR_ELEM_P2P_INV_REQ: - case VENDOR_ELEM_P2P_INV_RESP: - case VENDOR_ELEM_P2P_ASSOC_REQ: - return wpa_s->parent; -#endif /* CONFIG_P2P */ - default: - return wpa_s; + struct wpabuf *buf; + size_t len; + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + + if (len == 0) { + buf = NULL; + } else { + buf = wpabuf_alloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) { + wpabuf_free(buf); + return -1; + } } + + wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); + return 0; } +#endif /* CONFIG_TESTING_OPTIONS */ + static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) { @@ -7803,7 +8232,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) frame = atoi(pos); if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); pos = os_strchr(pos, ' '); if (pos == NULL) @@ -7834,7 +8263,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) if (wpa_s->vendor_elem[frame] == NULL) { wpa_s->vendor_elem[frame] = buf; - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7845,7 +8274,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) wpabuf_put_buf(wpa_s->vendor_elem[frame], buf); wpabuf_free(buf); - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7858,7 +8287,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd, if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); if (wpa_s->vendor_elem[frame] == NULL) return 0; @@ -7876,12 +8305,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) size_t len; u8 *buf; struct ieee802_11_elems elems; - u8 *ie, *end; + int res; frame = atoi(pos); if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); pos = os_strchr(pos, ' '); if (pos == NULL) @@ -7891,7 +8320,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) if (*pos == '*') { wpabuf_free(wpa_s->vendor_elem[frame]); wpa_s->vendor_elem[frame] = NULL; - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7919,65 +8348,149 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) return -1; } - ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); - end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); - - for (; ie + 1 < end; ie += 2 + ie[1]) { - if (ie + len > end) - break; - if (os_memcmp(ie, buf, len) != 0) - continue; - - if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { - wpabuf_free(wpa_s->vendor_elem[frame]); - wpa_s->vendor_elem[frame] = NULL; - } else { - os_memmove(ie, ie + len, - end - (ie + len)); - wpa_s->vendor_elem[frame]->used -= len; - } - os_free(buf); - wpas_ctrl_vendor_elem_update(wpa_s); - return 0; - } - + res = wpas_vendor_elem_remove(wpa_s, frame, buf, len); os_free(buf); - - return -1; + return res; } static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep) { struct wpa_supplicant *wpa_s = ctx; + size_t len; + const u8 *data; - if (neighbor_rep) { - wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED - "length=%u", - (unsigned int) wpabuf_len(neighbor_rep)); - wpabuf_free(neighbor_rep); - } else { + /* + * Neighbor Report element (IEEE P802.11-REVmc/D5.0) + * BSSID[6] + * BSSID Information[4] + * Operating Class[1] + * Channel Number[1] + * PHY Type[1] + * Optional Subelements[variable] + */ +#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1) + + if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) { wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED); + goto out; + } + + data = wpabuf_head_u8(neighbor_rep); + len = wpabuf_len(neighbor_rep); + + while (len >= 2 + NR_IE_MIN_LEN) { + const u8 *nr; + char lci[256 * 2 + 1]; + char civic[256 * 2 + 1]; + u8 nr_len = data[1]; + const u8 *pos = data, *end; + + if (pos[0] != WLAN_EID_NEIGHBOR_REPORT || + nr_len < NR_IE_MIN_LEN) { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid Neighbor Report element: id=%u len=%u", + data[0], nr_len); + goto out; + } + + if (2U + nr_len > len) { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u", + data[0], len, nr_len); + goto out; + } + pos += 2; + end = pos + nr_len; + + nr = pos; + pos += NR_IE_MIN_LEN; + + lci[0] = '\0'; + civic[0] = '\0'; + while (end - pos > 2) { + u8 s_id, s_len; + + s_id = *pos++; + s_len = *pos++; + if (s_len > end - pos) + goto out; + if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) { + /* Measurement Token[1] */ + /* Measurement Report Mode[1] */ + /* Measurement Type[1] */ + /* Measurement Report[variable] */ + switch (pos[2]) { + case MEASURE_TYPE_LCI: + if (lci[0]) + break; + wpa_snprintf_hex(lci, sizeof(lci), + pos, s_len); + break; + case MEASURE_TYPE_LOCATION_CIVIC: + if (civic[0]) + break; + wpa_snprintf_hex(civic, sizeof(civic), + pos, s_len); + break; + } + } + + pos += s_len; + } + + wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED + "bssid=" MACSTR + " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s", + MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN), + nr[ETH_ALEN + 4], nr[ETH_ALEN + 5], + nr[ETH_ALEN + 6], + lci[0] ? " lci=" : "", lci, + civic[0] ? " civic=" : "", civic); + + data = end; + len -= 2 + nr_len; } + +out: + wpabuf_free(neighbor_rep); } -static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s, - char *cmd) +static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s, + char *cmd) { - struct wpa_ssid ssid; - struct wpa_ssid *ssid_p = NULL; - int ret = 0; + struct wpa_ssid_value ssid, *ssid_p = NULL; + int ret, lci = 0, civic = 0; + char *ssid_s; - if (os_strncmp(cmd, " ssid=", 6) == 0) { - ssid.ssid_len = os_strlen(cmd + 6); - if (ssid.ssid_len > SSID_MAX_LEN) + ssid_s = os_strstr(cmd, "ssid="); + if (ssid_s) { + if (ssid_parse(ssid_s + 5, &ssid)) { + wpa_printf(MSG_ERROR, + "CTRL: Send Neighbor Report: bad SSID"); return -1; - ssid.ssid = (u8 *) (cmd + 6); + } + ssid_p = &ssid; + + /* + * Move cmd after the SSID text that may include "lci" or + * "civic". + */ + cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' '); + if (cmd) + cmd++; + } - ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, + if (cmd && os_strstr(cmd, "lci")) + lci = 1; + + if (cmd && os_strstr(cmd, "civic")) + civic = 1; + + ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic, wpas_ctrl_neighbor_rep_cb, wpa_s); @@ -8062,10 +8575,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, } } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) { - /* simulate timeout to restart the sched scan */ - wpa_s->sched_scan_timed_out = 1; - wpa_s->prev_sched_ssid = NULL; - wpa_supplicant_cancel_sched_scan(wpa_s); + wpas_scan_restart_sched_scan(wpa_s); } return 0; } @@ -8091,12 +8601,8 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN, addr, mask); - if (wpa_s->sched_scanning && !wpa_s->pno) { - /* simulate timeout to restart the sched scan */ - wpa_s->sched_scan_timed_out = 1; - wpa_s->prev_sched_ssid = NULL; - wpa_supplicant_cancel_sched_scan(wpa_s); - } + if (wpa_s->sched_scanning && !wpa_s->pno) + wpas_scan_restart_sched_scan(wpa_s); } if (type & MAC_ADDR_RAND_PNO) { @@ -8112,6 +8618,29 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + size_t reply_len; + + reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen); +#ifdef CONFIG_AP + reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len], + buflen - reply_len); +#endif /* CONFIG_AP */ + return reply_len; +} + + +static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) +{ + wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); +#ifdef CONFIG_AP + wpas_ap_pmksa_cache_flush(wpa_s); +#endif /* CONFIG_AP */ +} + + static int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || @@ -8183,10 +8712,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); } else if (os_strcmp(buf, "PMKSA") == 0) { - reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply, - reply_size); + reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size); } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { - wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); + wpas_ctrl_iface_pmksa_flush(wpa_s); } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; @@ -8354,6 +8882,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s, buf + 18)) reply_len = -1; + } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) { + if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17)) + reply_len = -1; + } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) { + if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14)) + reply_len = -1; #endif /* CONFIG_MESH */ #ifdef CONFIG_P2P } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { @@ -8388,6 +8922,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { if (p2p_ctrl_group_add(wpa_s, buf + 14)) reply_len = -1; + } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) { + reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply, + reply_size); } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) reply_len = -1; @@ -8453,6 +8990,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) { if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0) reply_len = -1; + } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) { + if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) { + if (wpas_p2p_lo_stop(wpa_s)) + reply_len = -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { @@ -8506,10 +9049,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0) reply_len = -1; } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) { - if (hs20_icon_request(wpa_s, buf + 18) < 0) + if (hs20_icon_request(wpa_s, buf + 18, 0) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) { + if (hs20_icon_request(wpa_s, buf + 14, 1) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) { + reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size); + } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) { + if (del_hs20_icon(wpa_s, buf + 14) < 0) reply_len = -1; } else if (os_strcmp(buf, "FETCH_OSU") == 0) { - if (hs20_fetch_osu(wpa_s) < 0) + if (hs20_fetch_osu(wpa_s, 0) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) { + if (hs20_fetch_osu(wpa_s, 1) < 0) reply_len = -1; } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) { hs20_cancel_fetch_osu(wpa_s); @@ -8548,16 +9102,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpa_supplicant_ctrl_iface_list_networks( wpa_s, NULL, reply, reply_size); } else if (os_strcmp(buf, "DISCONNECT") == 0) { -#ifdef CONFIG_SME - wpa_s->sme.prev_bssid_set = 0; -#endif /* CONFIG_SME */ - wpa_s->reassociate = 0; - wpa_s->disconnected = 1; - wpa_supplicant_cancel_sched_scan(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); + wpas_request_disconnection(wpa_s); } else if (os_strcmp(buf, "SCAN") == 0) { wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); } else if (os_strncmp(buf, "SCAN ", 5) == 0) { @@ -8565,6 +9110,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); + } else if (os_strcmp(buf, "ABORT_SCAN") == 0) { + if (wpas_abort_ongoing_scan(wpa_s) < 0) + reply_len = -1; } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) reply_len = -1; @@ -8623,9 +9171,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( wpa_s->global, reply, reply_size); - } else if (os_strcmp(buf, "INTERFACES") == 0) { + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = wpa_supplicant_global_iface_interfaces( - wpa_s->global, reply, reply_size); + wpa_s->global, buf + 10, reply, reply_size); } else if (os_strncmp(buf, "BSS ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); @@ -8706,6 +9254,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { reply_len = wpa_supplicant_signal_poll(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) { + if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14)) + reply_len = -1; } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) { reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply, reply_size); @@ -8714,6 +9265,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_AUTOSCAN */ + } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { + reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply, + reply_size); #ifdef ANDROID } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, @@ -8744,6 +9298,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) { wpas_ctrl_iface_mgmt_tx_done(wpa_s); + } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) { + if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) { if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) reply_len = -1; @@ -8769,6 +9326,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "GET_FAIL") == 0) { reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) { + if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { + if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) + reply_len = -1; #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) @@ -8780,7 +9343,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0) reply_len = -1; } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) { - if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20)) + if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20)) reply_len = -1; } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { wpas_ctrl_iface_erp_flush(wpa_s); @@ -8813,10 +9376,11 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, struct wpa_supplicant *wpa_s; unsigned int create_iface = 0; u8 mac_addr[ETH_ALEN]; + enum wpa_driver_if_type type = WPA_IF_STATION; /* * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> - * TAB<bridge_ifname>[TAB<create>] + * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]] */ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); @@ -8884,9 +9448,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, if (!extra[0]) break; - if (os_strcmp(extra, "create") == 0) + if (os_strcmp(extra, "create") == 0) { create_iface = 1; - else { + if (!pos) + break; + + if (os_strcmp(pos, "sta") == 0) { + type = WPA_IF_STATION; + } else if (os_strcmp(pos, "ap") == 0) { + type = WPA_IF_AP_BSS; + } else { + wpa_printf(MSG_DEBUG, + "INTERFACE_ADD unsupported interface type: '%s'", + pos); + return -1; + } + } else { wpa_printf(MSG_DEBUG, "INTERFACE_ADD unsupported extra parameter: '%s'", extra); @@ -8899,7 +9476,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, iface.ifname); if (!global->ifaces) return -1; - if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname, + if (wpa_drv_if_add(global->ifaces, type, iface.ifname, NULL, NULL, NULL, mac_addr, NULL) < 0) { wpa_printf(MSG_ERROR, "CTRL_IFACE interface creation failed"); @@ -9008,18 +9585,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global, static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + const char *input, char *buf, int len) { int res; char *pos, *end; struct wpa_supplicant *wpa_s; + int show_ctrl = 0; + + if (input) + show_ctrl = !!os_strstr(input, "ctrl"); wpa_s = global->ifaces; pos = buf; end = buf + len; while (wpa_s) { - res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname); + if (show_ctrl) + res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n", + wpa_s->ifname, + wpa_s->conf->ctrl_interface ? + wpa_s->conf->ctrl_interface : "N/A"); + else + res = os_snprintf(pos, end - pos, "%s\n", + wpa_s->ifname); + if (os_snprintf_error(end - pos, res)) { *pos = '\0'; break; @@ -9085,6 +9675,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, "P2P_LISTEN ", "P2P_GROUP_REMOVE ", "P2P_GROUP_ADD ", + "P2P_GROUP_MEMBER ", "P2P_PROV_DISC ", "P2P_SERV_DISC_REQ ", "P2P_SERV_DISC_CANCEL_REQ ", @@ -9408,9 +9999,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( global, reply, reply_size); - } else if (os_strcmp(buf, "INTERFACES") == 0) { + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = wpa_supplicant_global_iface_interfaces( - global, reply, reply_size); + global, buf + 10, reply, reply_size); #ifdef CONFIG_FST } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) { reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11, @@ -9456,7 +10047,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, reply_size); #ifdef CONFIG_MODULE_TESTS } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { - int wpas_module_tests(void); if (wpas_module_tests() < 0) reply_len = -1; #endif /* CONFIG_MODULE_TESTS */ diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 76f69f2..0dc0937 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / UDP socket -based control interface - * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -48,13 +48,33 @@ struct ctrl_iface_priv { u8 cookie[COOKIE_LEN]; }; +struct ctrl_iface_global_priv { + int sock; + struct wpa_ctrl_dst *ctrl_dst; + u8 cookie[COOKIE_LEN]; +}; -static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + +static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, + const char *ifname, int sock, + struct wpa_ctrl_dst **head, int level, const char *buf, size_t len); -static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, +static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst) +{ + struct wpa_ctrl_dst *prev; + + while (dst) { + prev = dst; + dst = dst->next; + os_free(prev); + } +} + + +static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head, #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 *from, #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ @@ -73,8 +93,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, os_memcpy(&dst->addr, from, sizeof(*from)); dst->addrlen = fromlen; dst->debug_level = MSG_INFO; - dst->next = priv->ctrl_dst; - priv->ctrl_dst = dst; + dst->next = *head; + *head = dst; #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)), @@ -87,7 +107,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, } -static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, +static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head, #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 *from, #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ @@ -100,7 +120,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, char addr[INET6_ADDRSTRLEN]; #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ - dst = priv->ctrl_dst; + dst = *head; while (dst) { #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 if (from->sin6_port == dst->addr.sin6_port && @@ -118,7 +138,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, ntohs(from->sin_port)); #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (prev == NULL) - priv->ctrl_dst = dst->next; + *head = dst->next; else prev->next = dst->next; os_free(dst); @@ -282,14 +302,16 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, pos++; if (os_strcmp(pos, "ATTACH") == 0) { - if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) + if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, + &from, fromlen)) reply_len = 1; else { new_attached = 1; reply_len = 2; } } else if (os_strcmp(pos, "DETACH") == 0) { - if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) + if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, + &from, fromlen)) reply_len = 1; else reply_len = 2; @@ -327,9 +349,28 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, const char *txt, size_t len) { struct wpa_supplicant *wpa_s = ctx; - if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + + if (!wpa_s) return; - wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); + + if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) { + struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; + + if (priv->ctrl_dst) { + wpa_supplicant_ctrl_iface_send( + wpa_s, + type != WPA_MSG_PER_INTERFACE ? + NULL : wpa_s->ifname, + priv->sock, &priv->ctrl_dst, level, txt, len); + } + } + + if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface) + return; + + wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, + &wpa_s->ctrl_iface->ctrl_dst, + level, txt, len); } @@ -337,7 +378,9 @@ struct ctrl_iface_priv * wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { struct ctrl_iface_priv *priv; + char port_str[40]; int port = WPA_CTRL_IFACE_PORT; + char *pos; #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 addr; int domain = PF_INET6; @@ -356,6 +399,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) if (wpa_s->conf->ctrl_interface == NULL) return priv; + pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s", + wpa_s->conf->ctrl_interface); + goto fail; + } + } + priv->sock = socket(domain, SOCK_DGRAM, 0); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); @@ -392,6 +446,15 @@ try_again: goto fail; } + /* Update the ctrl_interface value to match the selected port */ + os_snprintf(port_str, sizeof(port_str), "udp:%d", port); + os_free(wpa_s->conf->ctrl_interface); + wpa_s->conf->ctrl_interface = os_strdup(port_str); + if (!wpa_s->conf->ctrl_interface) { + wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface"); + goto fail; + } + #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port); #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ @@ -412,8 +475,6 @@ fail: void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { - struct wpa_ctrl_dst *dst, *prev; - if (priv->sock > -1) { eloop_unregister_read_sock(priv->sock); if (priv->ctrl_dst) { @@ -430,22 +491,19 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) priv->sock = -1; } - dst = priv->ctrl_dst; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } + wpas_ctrl_iface_free_dst(priv->ctrl_dst); os_free(priv); } -static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, +static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, + const char *ifname, int sock, + struct wpa_ctrl_dst **head, int level, const char *buf, size_t len) { struct wpa_ctrl_dst *dst, *next; - char levelstr[10]; + char levelstr[64]; int idx; char *sbuf; int llen; @@ -453,11 +511,15 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, char addr[INET6_ADDRSTRLEN]; #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ - dst = priv->ctrl_dst; - if (priv->sock < 0 || dst == NULL) + dst = *head; + if (sock < 0 || dst == NULL) return; - os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + if (ifname) + os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>", + ifname, level); + else + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); llen = os_strlen(levelstr); sbuf = os_malloc(llen + len); @@ -481,7 +543,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, inet_ntoa(dst->addr.sin_addr), ntohs(dst->addr.sin_port)); #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ - if (sendto(priv->sock, sbuf, llen + len, 0, + if (sendto(sock, sbuf, llen + len, 0, (struct sockaddr *) &dst->addr, sizeof(dst->addr)) < 0) { wpa_printf(MSG_ERROR, @@ -490,7 +552,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, dst->errors++; if (dst->errors > 10) { wpa_supplicant_ctrl_iface_detach( - priv, &dst->addr, + head, &dst->addr, dst->addrlen); } } else @@ -513,12 +575,6 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) /* Global ctrl_iface */ -struct ctrl_iface_global_priv { - int sock; - u8 cookie[COOKIE_LEN]; -}; - - static char * wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, size_t *reply_len) @@ -546,9 +602,13 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_global_priv *priv = sock_ctx; char buf[256], *pos; int res; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 from; +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in from; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ socklen_t fromlen = sizeof(from); - char *reply; + char *reply = NULL; size_t reply_len; u8 cookie[COOKIE_LEN]; @@ -561,6 +621,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, } #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE +#ifndef CONFIG_CTRL_IFACE_UDP_IPV6 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { /* * The OS networking stack is expected to drop this kind of @@ -572,6 +633,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, "source %s", inet_ntoa(from.sin_addr)); return; } +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ buf[res] = '\0'; @@ -603,17 +665,34 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, while (*pos == ' ') pos++; - reply = wpa_supplicant_global_ctrl_iface_process(global, pos, - &reply_len); + if (os_strcmp(pos, "ATTACH") == 0) { + if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, + &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else if (os_strcmp(pos, "DETACH") == 0) { + if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, + &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else { + reply = wpa_supplicant_global_ctrl_iface_process(global, pos, + &reply_len); + } done: if (reply) { sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); os_free(reply); - } else if (reply_len) { + } else if (reply_len == 1) { sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen); + } else if (reply_len == 2) { + sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, + fromlen); } } @@ -623,6 +702,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) { struct ctrl_iface_global_priv *priv; struct sockaddr_in addr; + char *pos; int port = WPA_GLOBAL_CTRL_IFACE_PORT; priv = os_zalloc(sizeof(*priv)); @@ -637,6 +717,17 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) wpa_printf(MSG_DEBUG, "Global control interface '%s'", global->params.ctrl_interface); + pos = os_strstr(global->params.ctrl_interface, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s", + global->params.ctrl_interface); + goto fail; + } + } + priv->sock = socket(PF_INET, SOCK_DGRAM, 0); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); @@ -655,7 +746,7 @@ try_again: if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { port++; if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) < - WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT) + WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos) goto try_again; wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno)); goto fail; @@ -668,6 +759,7 @@ try_again: eloop_register_read_sock(priv->sock, wpa_supplicant_global_ctrl_iface_receive, global, priv); + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); return priv; @@ -686,5 +778,7 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) eloop_unregister_read_sock(priv->sock); close(priv->sock); } + + wpas_ctrl_iface_free_dst(priv->ctrl_dst); os_free(priv); } diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 11f2814..4db712f 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -15,7 +15,6 @@ #include <fcntl.h> #ifdef __linux__ #include <sys/ioctl.h> -#include <linux/sockios.h> #endif /* __linux__ */ #ifdef ANDROID #include <cutils/sockets.h> @@ -24,6 +23,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/list.h" +#include "common/ctrl_iface_common.h" #include "eapol_supp/eapol_supp_sm.h" #include "config.h" #include "wpa_supplicant_i.h" @@ -31,27 +31,13 @@ /* Per-interface ctrl_iface */ -/** - * struct wpa_ctrl_dst - Internal data structure of control interface monitors - * - * This structure is used to store information about registered control - * interface monitors into struct wpa_supplicant. This data is private to - * ctrl_iface_unix.c and should not be touched directly from other files. - */ -struct wpa_ctrl_dst { - struct dl_list list; - struct sockaddr_un addr; - socklen_t addrlen; - int debug_level; - int errors; -}; - - struct ctrl_iface_priv { struct wpa_supplicant *wpa_s; int sock; struct dl_list ctrl_dst; int android_control_socket; + struct dl_list msg_queue; + unsigned int throttle_count; }; @@ -60,6 +46,17 @@ struct ctrl_iface_global_priv { int sock; struct dl_list ctrl_dst; int android_control_socket; + struct dl_list msg_queue; + unsigned int throttle_count; +}; + +struct ctrl_iface_msg { + struct dl_list list; + struct wpa_supplicant *wpa_s; + int level; + enum wpa_msg_type type; + const char *txt; + size_t len; }; @@ -92,7 +89,7 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) sndbuf = -1; - if (ioctl(sock, SIOCOUTQ, &outq) < 0) + if (ioctl(sock, TIOCOUTQ, &outq) < 0) outq = -1; wpa_printf(level, @@ -103,81 +100,29 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, int global) { - struct wpa_ctrl_dst *dst; - char addr_txt[200]; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dl_list_add(ctrl_dst, &dst->list); - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s", - global ? "global " : "", addr_txt); - return 0; + return ctrl_iface_attach(ctrl_dst, from, fromlen); } static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - char addr_txt[200]; - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", - addr_txt); - dl_list_del(&dst->list); - os_free(dst); - return 0; - } - } - return -1; + return ctrl_iface_detach(ctrl_dst, from, fromlen); } static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, char *level) { - struct wpa_ctrl_dst *dst; - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - char addr_txt[200]; - dst->debug_level = atoi(level); - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", - dst->debug_level, addr_txt); - return 0; - } - } - - return -1; + return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level); } @@ -188,7 +133,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_priv *priv = sock_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len = 0; @@ -334,33 +279,209 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) } +static int wpas_ctrl_iface_throttle(int sock) +{ +#ifdef __linux__ + socklen_t optlen; + int sndbuf, outq; + + optlen = sizeof(sndbuf); + sndbuf = 0; + if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 || + ioctl(sock, TIOCOUTQ, &outq) < 0 || + sndbuf <= 0 || outq < 0) + return 0; + return outq > sndbuf / 2; +#else /* __linux__ */ + return 0; +#endif /* __linux__ */ +} + + +static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *gpriv; + struct ctrl_iface_msg *msg; + + gpriv = global->ctrl_iface; + while (gpriv && !dl_list_empty(&gpriv->msg_queue) && + !wpas_ctrl_iface_throttle(gpriv->sock)) { + msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg, + list); + if (!msg) + break; + dl_list_del(&msg->list); + wpa_supplicant_ctrl_iface_send( + msg->wpa_s, + msg->type != WPA_MSG_PER_INTERFACE ? + NULL : msg->wpa_s->ifname, + gpriv->sock, &gpriv->ctrl_dst, msg->level, + msg->txt, msg->len, NULL, gpriv); + os_free(msg); + } +} + + +static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + struct ctrl_iface_msg *msg; + + priv = wpa_s->ctrl_iface; + while (priv && !dl_list_empty(&priv->msg_queue) && + !wpas_ctrl_iface_throttle(priv->sock)) { + msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg, + list); + if (!msg) + break; + dl_list_del(&msg->list); + wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock, + &priv->ctrl_dst, msg->level, + msg->txt, msg->len, priv, NULL); + os_free(msg); + } +} + + +static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct ctrl_iface_priv *priv; + struct ctrl_iface_global_priv *gpriv; + int sock = -1, gsock = -1; + + wpas_ctrl_msg_send_pending_global(wpa_s->global); + wpas_ctrl_msg_send_pending_iface(wpa_s); + + priv = wpa_s->ctrl_iface; + if (priv && !dl_list_empty(&priv->msg_queue)) + sock = priv->sock; + + gpriv = wpa_s->global->ctrl_iface; + if (gpriv && !dl_list_empty(&gpriv->msg_queue)) + gsock = gpriv->sock; + + if (sock > -1 || gsock > -1) { + /* Continue pending message transmission from a timeout */ + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)", + sock, gsock); + eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout, + wpa_s, NULL); + } +} + + +static void wpas_ctrl_msg_queue(struct dl_list *queue, + struct wpa_supplicant *wpa_s, int level, + enum wpa_msg_type type, + const char *txt, size_t len) +{ + struct ctrl_iface_msg *msg; + + msg = os_zalloc(sizeof(*msg) + len); + if (!msg) + return; + + msg->wpa_s = wpa_s; + msg->level = level; + msg->type = type; + os_memcpy(msg + 1, txt, len); + msg->txt = (const char *) (msg + 1); + msg->len = len; + dl_list_add_tail(queue, &msg->list); + eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL); + eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL); +} + + +static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count, + struct dl_list *queue) +{ + struct ctrl_iface_msg *msg; + + if (throttle_count < 2000) + return; + + msg = dl_list_first(queue, struct ctrl_iface_msg, list); + if (msg) { + wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message"); + dl_list_del(&msg->list); + os_free(msg); + } +} + + static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, enum wpa_msg_type type, const char *txt, size_t len) { struct wpa_supplicant *wpa_s = ctx; + struct ctrl_iface_priv *priv; + struct ctrl_iface_global_priv *gpriv; if (wpa_s == NULL) return; - if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) { - struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; - if (!dl_list_empty(&priv->ctrl_dst)) { + gpriv = wpa_s->global->ctrl_iface; + + if (type != WPA_MSG_NO_GLOBAL && gpriv && + !dl_list_empty(&gpriv->ctrl_dst)) { + if (!dl_list_empty(&gpriv->msg_queue) || + wpas_ctrl_iface_throttle(gpriv->sock)) { + if (gpriv->throttle_count == 0) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle global event message for sock %d", + gpriv->sock); + } + gpriv->throttle_count++; + wpas_ctrl_msg_queue_limit(gpriv->throttle_count, + &gpriv->msg_queue); + wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level, + type, txt, len); + } else { + if (gpriv->throttle_count) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle %u global event message(s) for sock %d", + gpriv->throttle_count, gpriv->sock); + } + gpriv->throttle_count = 0; wpa_supplicant_ctrl_iface_send( wpa_s, type != WPA_MSG_PER_INTERFACE ? NULL : wpa_s->ifname, - priv->sock, &priv->ctrl_dst, level, txt, len, - NULL, priv); + gpriv->sock, &gpriv->ctrl_dst, level, + txt, len, NULL, gpriv); } } - if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL) - return; - wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, - &wpa_s->ctrl_iface->ctrl_dst, - level, txt, len, wpa_s->ctrl_iface, - NULL); + priv = wpa_s->ctrl_iface; + + if (type != WPA_MSG_ONLY_GLOBAL && priv) { + if (!dl_list_empty(&priv->msg_queue) || + wpas_ctrl_iface_throttle(priv->sock)) { + if (priv->throttle_count == 0) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle event message for sock %d", + priv->sock); + } + priv->throttle_count++; + wpas_ctrl_msg_queue_limit(priv->throttle_count, + &priv->msg_queue); + wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level, + type, txt, len); + } else { + if (priv->throttle_count) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle %u event message(s) for sock %d", + priv->throttle_count, priv->sock); + } + priv->throttle_count = 0; + wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock, + &priv->ctrl_dst, level, + txt, len, priv, NULL); + } + } } @@ -578,6 +699,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) if (priv == NULL) return NULL; dl_list_init(&priv->ctrl_dst); + dl_list_init(&priv->msg_queue); priv->wpa_s = wpa_s; priv->sock = -1; @@ -671,6 +793,8 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { struct wpa_ctrl_dst *dst, *prev; + struct ctrl_iface_msg *msg, *prev_msg; + struct ctrl_iface_global_priv *gpriv; if (priv->sock > -1) { char *fname; @@ -724,8 +848,26 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) free_dst: dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, - list) + list) { + dl_list_del(&dst->list); os_free(dst); + } + dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue, + struct ctrl_iface_msg, list) { + dl_list_del(&msg->list); + os_free(msg); + } + gpriv = priv->wpa_s->global->ctrl_iface; + if (gpriv) { + dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue, + struct ctrl_iface_msg, list) { + if (msg->wpa_s == priv->wpa_s) { + dl_list_del(&msg->list); + os_free(msg); + } + } + } + eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL); os_free(priv); } @@ -785,33 +927,31 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { int _errno; - char addr_txt[200]; + char txt[200]; if (level < dst->debug_level) continue; - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); msg.msg_name = (void *) &dst->addr; msg.msg_namelen = dst->addrlen; wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len); if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { - wpa_printf(MSG_MSGDUMP, - "CTRL_IFACE monitor sent successfully to %s", - addr_txt); + sockaddr_print(MSG_MSGDUMP, + "CTRL_IFACE monitor sent successfully to", + &dst->addr, dst->addrlen); dst->errors = 0; continue; } _errno = errno; - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", - addr_txt, errno, strerror(errno)); + os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for", + _errno, strerror(_errno)); + sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen); dst->errors++; if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { - wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", - addr_txt); + sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:", + &dst->addr, dst->addrlen); wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, dst->addrlen); } @@ -845,9 +985,12 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { char buf[256]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); + if (priv->sock == -1) + return; + for (;;) { wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " "attach", priv->wpa_s->ifname); @@ -905,7 +1048,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_global_priv *priv = sock_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len; @@ -1155,6 +1298,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) if (priv == NULL) return NULL; dl_list_init(&priv->ctrl_dst); + dl_list_init(&priv->msg_queue); priv->global = global; priv->sock = -1; @@ -1204,6 +1348,7 @@ void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { struct wpa_ctrl_dst *dst, *prev; + struct ctrl_iface_msg *msg, *prev_msg; if (priv->sock >= 0) { eloop_unregister_read_sock(priv->sock); @@ -1212,7 +1357,14 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) if (priv->global->params.ctrl_interface) unlink(priv->global->params.ctrl_interface); dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, - list) + list) { + dl_list_del(&dst->list); os_free(dst); + } + dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue, + struct ctrl_iface_msg, list) { + dl_list_del(&msg->list); + os_free(msg); + } os_free(priv); } diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf index c091234..382dcb3 100644 --- a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf +++ b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf @@ -17,11 +17,9 @@ <policy context="default"> <deny own="fi.epitest.hostap.WPASupplicant"/> <deny send_destination="fi.epitest.hostap.WPASupplicant"/> - <deny send_interface="fi.epitest.hostap.WPASupplicant"/> <deny own="fi.w1.wpa_supplicant1"/> <deny send_destination="fi.w1.wpa_supplicant1"/> - <deny send_interface="fi.w1.wpa_supplicant1"/> <deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> </policy> </busconfig> diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/wpa_supplicant/dbus/dbus_common_i.h index a551ccd..95eb4bc 100644 --- a/wpa_supplicant/dbus/dbus_common_i.h +++ b/wpa_supplicant/dbus/dbus_common_i.h @@ -13,6 +13,8 @@ #include <dbus/dbus.h> +struct wpa_dbus_property_desc; + struct wpas_dbus_priv { DBusConnection *con; int should_dispatch; @@ -20,9 +22,13 @@ struct wpas_dbus_priv { u32 next_objid; int dbus_new_initialized; -#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP) +#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) + struct wpa_dbus_property_desc *all_interface_properties; + int globals_start; +#if defined(CONFIG_AP) int dbus_noc_refcnt; -#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */ +#endif /* CONFIG_AP */ +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ }; #endif /* DBUS_COMMON_I_H */ diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c index a0c44eb..e4e9b8d 100644 --- a/wpa_supplicant/dbus/dbus_dict_helpers.c +++ b/wpa_supplicant/dbus/dbus_dict_helpers.c @@ -205,24 +205,6 @@ dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, /** - * Add a byte entry to the dict. - * - * @param iter_dict A valid DBusMessageIter returned from - * wpa_dbus_dict_open_write() - * @param key The key of the dict item - * @param value The byte value - * @return TRUE on success, FALSE on failure - * - */ -dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, - const char *key, const char value) -{ - return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE, - &value); -} - - -/** * Add a boolean entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from @@ -317,62 +299,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, /** - * Add a 64-bit integer entry to the dict. - * - * @param iter_dict A valid DBusMessageIter returned from - * wpa_dbus_dict_open_write() - * @param key The key of the dict item - * @param value The 64-bit integer value - * @return TRUE on success, FALSE on failure - * - */ -dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, - const char *key, - const dbus_int64_t value) -{ - return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64, - &value); -} - - -/** - * Add a 64-bit unsigned integer entry to the dict. - * - * @param iter_dict A valid DBusMessageIter returned from - * wpa_dbus_dict_open_write() - * @param key The key of the dict item - * @param value The 64-bit unsigned integer value - * @return TRUE on success, FALSE on failure - * - */ -dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, - const char *key, - const dbus_uint64_t value) -{ - return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, - &value); -} - - -/** - * Add a double-precision floating point entry to the dict. - * - * @param iter_dict A valid DBusMessageIter returned from - * wpa_dbus_dict_open_write() - * @param key The key of the dict item - * @param value The double-precision floating point value - * @return TRUE on success, FALSE on failure - * - */ -dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, - const char *key, const double value) -{ - return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, - &value); -} - - -/** * Add a DBus object path entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h index b068431..94a0efd 100644 --- a/wpa_supplicant/dbus/dbus_dict_helpers.h +++ b/wpa_supplicant/dbus/dbus_dict_helpers.h @@ -26,9 +26,6 @@ const char * wpa_dbus_type_as_string(const int type); dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, const char *key, const char *value); -dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, - const char *key, const char value); - dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, const char *key, const dbus_bool_t value); @@ -49,18 +46,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, const char *key, const dbus_uint32_t value); -dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, - const char *key, - const dbus_int64_t value); - -dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, - const char *key, - const dbus_uint64_t value); - -dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, - const char *key, - const double value); - dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, const char *key, const char *value); diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 67d0e28..27b3012 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -1207,7 +1207,7 @@ static int match_group_where_peer_is_client(struct p2p_group *group, cfg->ssid_len); if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) { wpas_dbus_signal_peer_groups_changed( - data->wpa_s->parent, data->info->p2p_device_addr); + data->wpa_s->p2pdev, data->info->p2p_device_addr); return 0; } @@ -1224,7 +1224,7 @@ static void signal_peer_groups_changed(struct p2p_peer_info *info, wpa_s_go = wpas_get_p2p_client_iface(data->wpa_s, info->p2p_device_addr); if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) { - wpas_dbus_signal_peer_groups_changed(data->wpa_s->parent, + wpas_dbus_signal_peer_groups_changed(data->wpa_s->p2pdev, info->p2p_device_addr); return; } @@ -1254,14 +1254,11 @@ static void peer_groups_changed(struct wpa_supplicant *wpa_s) * irrespective of the role (client/GO) of the current device * * @wpa_s: %wpa_supplicant network interface data - * @ssid: SSID object * @client: this device is P2P client - * @network_id: network id of the group started, use instead of ssid->id - * to account for persistent groups + * @persistent: 0 - non persistent group, 1 - persistent group */ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, - int client, int network_id) + int client, int persistent) { DBusMessage *msg; DBusMessageIter iter, dict_iter; @@ -1300,6 +1297,7 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, wpa_s->dbus_new_path) || !wpa_dbus_dict_append_string(&dict_iter, "role", client ? "client" : "GO") || + !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) || !wpa_dbus_dict_append_object_path(&dict_iter, "group_object", wpa_s->dbus_groupobj_path) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) { @@ -1950,6 +1948,7 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, } dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); } @@ -2000,6 +1999,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, prop = "DisconnectReason"; flush = TRUE; break; + case WPAS_DBUS_PROP_ASSOC_STATUS_CODE: + prop = "AssocStatusCode"; + flush = TRUE; + break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); @@ -2172,41 +2175,54 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = { END_ARGS } }, + { "ExpectDisconnect", WPAS_DBUS_NEW_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_expect_disconnect, + { + END_ARGS + } + }, { NULL, NULL, NULL, { END_ARGS } } }; static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = { { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s", wpas_dbus_getter_debug_level, - wpas_dbus_setter_debug_level + wpas_dbus_setter_debug_level, + NULL }, { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b", wpas_dbus_getter_debug_timestamp, - wpas_dbus_setter_debug_timestamp + wpas_dbus_setter_debug_timestamp, + NULL }, { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b", wpas_dbus_getter_debug_show_keys, - wpas_dbus_setter_debug_show_keys + wpas_dbus_setter_debug_show_keys, + NULL }, { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao", wpas_dbus_getter_interfaces, + NULL, NULL }, { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as", wpas_dbus_getter_eap_methods, + NULL, NULL }, { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as", wpas_dbus_getter_global_capabilities, + NULL, NULL }, #ifdef CONFIG_WIFI_DISPLAY { "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay", wpas_dbus_getter_global_wfd_ies, - wpas_dbus_setter_global_wfd_ies + wpas_dbus_setter_global_wfd_ies, + NULL }, #endif /* CONFIG_WIFI_DISPLAY */ - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = { @@ -2234,12 +2250,50 @@ static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = { }; +static char * uscore_to_dbus(const char *uscore) +{ + const char *p = uscore; + char *str, *s; + dbus_bool_t last_was_uscore = TRUE; + + s = str = os_zalloc(os_strlen(uscore) + 1); + if (!str) + return NULL; + while (p && *p) { + if (*p == '_') { + last_was_uscore = TRUE; + } else { + *s++ = last_was_uscore ? toupper(*p) : *p; + last_was_uscore = FALSE; + } + p++; + } + + return str; +} + + +static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv); + + +static void wpa_dbus_ctrl_iface_props_deinit(struct wpas_dbus_priv *priv) +{ + int idx = priv->globals_start; + + /* Free all allocated property values */ + while (priv->all_interface_properties[idx].dbus_property) + os_free((char *) + priv->all_interface_properties[idx++].dbus_property); + os_free((char *) priv->all_interface_properties); +} + + /** * wpas_dbus_ctrl_iface_init - Initialize dbus control interface * @global: Pointer to global data from wpa_supplicant_init() * Returns: 0 on success or -1 on failure * - * Initialize the dbus control interface for wpa_supplicantand and start + * Initialize the dbus control interface for wpa_supplicant and start * receiving commands from external programs over the bus. */ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv) @@ -2247,11 +2301,18 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv) struct wpa_dbus_object_desc *obj_desc; int ret; + ret = wpa_dbus_ctrl_iface_props_init(priv); + if (ret < 0) { + wpa_printf(MSG_ERROR, + "dbus: Not enough memory to init interface properties"); + return -1; + } + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory to create object description"); - return -1; + goto error; } wpas_dbus_register(obj_desc, priv->global, NULL, @@ -2264,31 +2325,36 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv) ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH, WPAS_DBUS_NEW_SERVICE, obj_desc); - if (ret < 0) + if (ret < 0) { free_dbus_object_desc(obj_desc); - else - priv->dbus_new_initialized = 1; + goto error; + } - return ret; + priv->dbus_new_initialized = 1; + return 0; + +error: + wpa_dbus_ctrl_iface_props_deinit(priv); + return -1; } /** * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for * wpa_supplicant - * @iface: Pointer to dbus private data from wpas_dbus_init() + * @priv: Pointer to dbus private data from wpas_dbus_init() * * Deinitialize the dbus control interface that was initialized with * wpas_dbus_ctrl_iface_init(). */ -void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface) +void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *priv) { - if (!iface->dbus_new_initialized) + if (!priv->dbus_new_initialized) return; wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'", WPAS_DBUS_NEW_PATH); - dbus_connection_unregister_object_path(iface->con, - WPAS_DBUS_NEW_PATH); + dbus_connection_unregister_object_path(priv->con, WPAS_DBUS_NEW_PATH); + wpa_dbus_ctrl_iface_props_deinit(priv); } @@ -2301,13 +2367,15 @@ static void wpa_dbus_free(void *ptr) static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = { { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}", wpas_dbus_getter_network_properties, - wpas_dbus_setter_network_properties + wpas_dbus_setter_network_properties, + NULL }, { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b", wpas_dbus_getter_enabled, - wpas_dbus_setter_enabled + wpas_dbus_setter_enabled, + NULL }, - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -2446,53 +2514,65 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid) static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = { { "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", wpas_dbus_getter_bss_ssid, + NULL, NULL }, { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", wpas_dbus_getter_bss_bssid, + NULL, NULL }, { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b", wpas_dbus_getter_bss_privacy, + NULL, NULL }, { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s", wpas_dbus_getter_bss_mode, + NULL, NULL }, { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n", wpas_dbus_getter_bss_signal, + NULL, NULL }, { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q", wpas_dbus_getter_bss_frequency, + NULL, NULL }, { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au", wpas_dbus_getter_bss_rates, + NULL, NULL }, { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", wpas_dbus_getter_bss_wpa, + NULL, NULL }, { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", wpas_dbus_getter_bss_rsn, + NULL, NULL }, { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", wpas_dbus_getter_bss_wps, + NULL, NULL }, { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay", wpas_dbus_getter_bss_ies, + NULL, NULL }, { "Age", WPAS_DBUS_NEW_IFACE_BSS, "u", wpas_dbus_getter_bss_age, + NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -2992,131 +3072,202 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { } }, #endif /* CONFIG_TDLS */ + { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add, + { + { "frame_id", "i", ARG_IN }, + { "ielems", "ay", ARG_IN }, + END_ARGS + } + }, + { "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get, + { + { "frame_id", "i", ARG_IN }, + { "ielems", "ay", ARG_OUT }, + END_ARGS + } + }, + { "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove, + { + { "frame_id", "i", ARG_IN }, + { "ielems", "ay", ARG_IN }, + END_ARGS + } + }, +#ifndef CONFIG_NO_CONFIG_WRITE + { "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_save_config, + { + END_ARGS + } + }, +#endif /* CONFIG_NO_CONFIG_WRITE */ { NULL, NULL, NULL, { END_ARGS } } }; static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}", wpas_dbus_getter_capabilities, + NULL, NULL }, { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_state, + NULL, NULL }, { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", wpas_dbus_getter_scanning, + NULL, NULL }, { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_ap_scan, - wpas_dbus_setter_ap_scan + wpas_dbus_setter_ap_scan, + NULL }, { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_bss_expire_age, - wpas_dbus_setter_bss_expire_age + wpas_dbus_setter_bss_expire_age, + NULL }, { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_bss_expire_count, - wpas_dbus_setter_bss_expire_count + wpas_dbus_setter_bss_expire_count, + NULL }, { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_country, - wpas_dbus_setter_country + wpas_dbus_setter_country, + NULL }, { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_ifname, + NULL, NULL }, { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_driver, + NULL, NULL }, { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_bridge_ifname, + NULL, + NULL + }, + { "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_config_file, + NULL, NULL }, { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", wpas_dbus_getter_current_bss, + NULL, NULL }, { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", wpas_dbus_getter_current_network, + NULL, NULL }, { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_current_auth_mode, + NULL, NULL }, { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}", wpas_dbus_getter_blobs, + NULL, NULL }, { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", wpas_dbus_getter_bsss, + NULL, NULL }, { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", wpas_dbus_getter_networks, + NULL, NULL }, { "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", wpas_dbus_getter_fast_reauth, - wpas_dbus_setter_fast_reauth + wpas_dbus_setter_fast_reauth, + NULL }, { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", wpas_dbus_getter_scan_interval, - wpas_dbus_setter_scan_interval + wpas_dbus_setter_scan_interval, + NULL }, { "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_pkcs11_engine_path, + NULL, NULL }, { "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_pkcs11_module_path, + NULL, NULL }, #ifdef CONFIG_WPS { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b", wpas_dbus_getter_process_credentials, - wpas_dbus_setter_process_credentials + wpas_dbus_setter_process_credentials, + NULL }, { "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s", wpas_dbus_getter_config_methods, - wpas_dbus_setter_config_methods + wpas_dbus_setter_config_methods, + NULL }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}", wpas_dbus_getter_p2p_device_config, - wpas_dbus_setter_p2p_device_config + wpas_dbus_setter_p2p_device_config, + NULL }, { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao", wpas_dbus_getter_p2p_peers, + NULL, NULL }, { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s", wpas_dbus_getter_p2p_role, + NULL, NULL }, { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o", wpas_dbus_getter_p2p_group, + NULL, NULL }, { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o", wpas_dbus_getter_p2p_peergo, + NULL, NULL }, { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao", wpas_dbus_getter_persistent_groups, + NULL, NULL }, #endif /* CONFIG_P2P */ { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", wpas_dbus_getter_disconnect_reason, + NULL, + NULL + }, + { "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", + wpas_dbus_getter_assoc_status_code, + NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { @@ -3206,6 +3357,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { END_ARGS } }, + { "DeviceFoundProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "path", "o", ARG_OUT }, @@ -3390,6 +3548,77 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { }; +static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv) +{ + size_t all_size; + unsigned int i, j, count, num_const, num_globals; + const char *global_name; + static const char * const ignored_globals[] = { + "bss_expiration_age", "bss_expiration_scan_count", + "ap_scan", "country", "fast_reauth", + "pkcs11_engine_path", "pkcs11_module_path" + }; + + /* wpas_dbus_interface_properties terminates with a NULL element */ + num_const = ARRAY_SIZE(wpas_dbus_interface_properties) - 1; + + num_globals = wpa_config_get_num_global_field_names(); + priv->globals_start = num_const; + + /* allocate enough for all properties + terminating NULL element */ + all_size = (num_globals + num_const + 1) * + sizeof(wpas_dbus_interface_properties[0]); + priv->all_interface_properties = os_zalloc(all_size); + if (!priv->all_interface_properties) { + wpa_printf(MSG_ERROR, + "dbus: Not enough memory for interface properties"); + return -1; + } + + /* Copy constant interface properties to the start of the array */ + os_memcpy(priv->all_interface_properties, + wpas_dbus_interface_properties, + sizeof(wpas_dbus_interface_properties)); + + /* Dynamically construct interface global properties */ + for (i = 0, count = num_const; i < num_globals; i++) { + struct wpa_dbus_property_desc *desc; + int no_var = 0; + + /* ignore globals that are actually just methods */ + global_name = wpa_config_get_global_field_name(i, &no_var); + if (no_var) + continue; + /* Ignore fields already explicitly exposed */ + for (j = 0; j < ARRAY_SIZE(ignored_globals); j++) { + if (os_strcmp(global_name, ignored_globals[j]) == 0) + break; + } + if (j < ARRAY_SIZE(ignored_globals)) + continue; + + desc = &priv->all_interface_properties[count++]; + desc->dbus_property = uscore_to_dbus(global_name); + if (!desc->dbus_property) { + wpa_printf(MSG_ERROR, + "dbus: Not enough memory for D-Bus property name"); + goto error; + } + desc->dbus_interface = WPAS_DBUS_NEW_IFACE_INTERFACE; + desc->type = "s"; + desc->getter = wpas_dbus_getter_iface_global; + desc->setter = wpas_dbus_setter_iface_global; + desc->data = global_name; + } + + return 0; + +error: + wpa_dbus_ctrl_iface_props_deinit(priv); + return -1; +} + + /** * wpas_dbus_register_interface - Register an interface with D-Bus * @wpa_s: wpa_supplicant interface structure @@ -3397,7 +3626,6 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { */ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) { - struct wpa_dbus_object_desc *obj_desc = NULL; struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; int next; @@ -3423,7 +3651,7 @@ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) } wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods, - wpas_dbus_interface_properties, + ctrl_iface->all_interface_properties, wpas_dbus_interface_signals); wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'", @@ -3489,65 +3717,80 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s) static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = { { "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", wpas_dbus_getter_p2p_peer_device_name, + NULL, NULL }, { "Manufacturer", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", wpas_dbus_getter_p2p_peer_manufacturer, + NULL, NULL }, { "ModelName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", wpas_dbus_getter_p2p_peer_modelname, + NULL, NULL }, { "ModelNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", wpas_dbus_getter_p2p_peer_modelnumber, + NULL, NULL }, { "SerialNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", wpas_dbus_getter_p2p_peer_serialnumber, + NULL, NULL }, { "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", wpas_dbus_getter_p2p_peer_primary_device_type, + NULL, NULL }, { "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q", wpas_dbus_getter_p2p_peer_config_method, + NULL, NULL }, { "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i", wpas_dbus_getter_p2p_peer_level, + NULL, NULL }, { "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y", wpas_dbus_getter_p2p_peer_device_capability, + NULL, NULL }, { "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y", wpas_dbus_getter_p2p_peer_group_capability, + NULL, NULL }, { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay", wpas_dbus_getter_p2p_peer_secondary_device_types, + NULL, NULL }, { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay", wpas_dbus_getter_p2p_peer_vendor_extension, + NULL, NULL }, { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", wpas_dbus_getter_p2p_peer_ies, + NULL, NULL }, { "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", wpas_dbus_getter_p2p_peer_device_address, + NULL, NULL }, { "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao", wpas_dbus_getter_p2p_peer_groups, + NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = { @@ -3569,12 +3812,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = { * In case of peer objects, it would be emitted by either * the "interface object" or by "peer objects" * @sig_name: signal name - DeviceFound + * @properties: Whether to add a second argument with object properties * - * Notify listeners about event related with newly found p2p peer device + * Notify listeners about event related with p2p peer device */ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr, const char *interface, - const char *sig_name) + const char *sig_name, int properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; @@ -3602,7 +3846,10 @@ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s, dbus_message_iter_init_append(msg, &iter); path = peer_obj_path; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, - &path)) + &path) || + (properties && !wpa_dbus_get_object_properties( + iface, peer_obj_path, WPAS_DBUS_NEW_IFACE_P2P_PEER, + &iter))) wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); else dbus_connection_send(iface->con, msg, NULL); @@ -3623,7 +3870,11 @@ void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, { wpas_dbus_signal_peer(wpa_s, dev_addr, WPAS_DBUS_NEW_IFACE_P2PDEVICE, - "DeviceFound"); + "DeviceFound", FALSE); + + wpas_dbus_signal_peer(wpa_s, dev_addr, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "DeviceFoundProperties", TRUE); } /** @@ -3638,7 +3889,7 @@ void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, { wpas_dbus_signal_peer(wpa_s, dev_addr, WPAS_DBUS_NEW_IFACE_P2PDEVICE, - "DeviceLost"); + "DeviceLost", FALSE); } /** @@ -3805,41 +4056,50 @@ void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s, static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = { { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao", wpas_dbus_getter_p2p_group_members, + NULL, NULL }, { "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o", wpas_dbus_getter_p2p_group, + NULL, NULL }, { "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s", wpas_dbus_getter_p2p_role, + NULL, NULL }, { "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", wpas_dbus_getter_p2p_group_ssid, + NULL, NULL }, { "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", wpas_dbus_getter_p2p_group_bssid, + NULL, NULL }, { "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q", wpas_dbus_getter_p2p_group_frequency, + NULL, NULL }, { "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s", wpas_dbus_getter_p2p_group_passphrase, + NULL, NULL }, { "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", wpas_dbus_getter_p2p_group_psk, + NULL, NULL }, { "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay", wpas_dbus_getter_p2p_group_vendor_ext, - wpas_dbus_setter_p2p_group_vendor_ext + wpas_dbus_setter_p2p_group_vendor_ext, + NULL }, - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = { @@ -3966,9 +4226,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_persistent_group_properties[] = { { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}", wpas_dbus_getter_persistent_group_properties, - wpas_dbus_setter_persistent_group_properties + wpas_dbus_setter_persistent_group_properties, + NULL }, - { NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL } }; /* No signals intended for persistent group objects */ diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index 6d240ff..d64fcee 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -29,6 +29,7 @@ enum wpas_dbus_prop { WPAS_DBUS_PROP_CURRENT_AUTH_MODE, WPAS_DBUS_PROP_BSSS, WPAS_DBUS_PROP_DISCONNECT_REASON, + WPAS_DBUS_PROP_ASSOC_STATUS_CODE, }; enum wpas_dbus_bss_prop { @@ -189,8 +190,7 @@ 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, - const struct wpa_ssid *ssid, - int client, int network_id); + int client, int persistent); 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, @@ -400,8 +400,7 @@ 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, - const struct wpa_ssid *ssid, - int client, int network_id) + int client, int persistent) { } diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 67562a5..e11dd36 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -435,7 +435,8 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, for (i = 0; i < array_len; i++) { if (!dbus_message_iter_append_basic(&array_iter, type, - array + i * element_size)) { + (const char *) array + + i * element_size)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 2.5", __func__); @@ -711,9 +712,9 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, * * Getter for "DebugLevel" property. */ -dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_debug_level( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { const char *str; int idx = wpa_debug_level; @@ -737,9 +738,9 @@ dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, * * Getter for "DebugTimestamp" property. */ -dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_debug_timestamp( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &wpa_debug_timestamp, error); @@ -756,9 +757,9 @@ dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, * * Getter for "DebugShowKeys" property. */ -dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_debug_show_keys( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &wpa_debug_show_keys, error); @@ -774,8 +775,9 @@ dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, * * Setter for "DebugLevel" property. */ -dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_setter_debug_level( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; const char *str = NULL; @@ -812,9 +814,9 @@ dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, * * Setter for "DebugTimestamp" property. */ -dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_debug_timestamp( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; dbus_bool_t val; @@ -838,9 +840,9 @@ dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, * * Setter for "DebugShowKeys" property. */ -dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_debug_show_keys( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; dbus_bool_t val; @@ -867,9 +869,9 @@ dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, * by dbus clients to return list of registered interfaces objects * paths */ -dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_interfaces( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; struct wpa_supplicant *wpa_s; @@ -912,8 +914,9 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, * Getter for "EapMethods" property. Handles requests * by dbus clients to return list of strings with supported EAP methods */ -dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_eap_methods( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { char **eap_methods; size_t num_items = 0; @@ -948,9 +951,9 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, * return a list of strings with supported capabilities like AP, RSN IBSS, * and P2P that are determined at compile time. */ -dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter, - DBusError *error, - void *user_data) +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 }; size_t num_items = 0; @@ -1472,10 +1475,7 @@ DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s) { if (wpa_s->current_ssid != NULL) { - wpa_s->disconnected = 1; - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - + wpas_request_disconnection(wpa_s); return NULL; } @@ -1504,7 +1504,7 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, dbus_message_iter_init(message, &iter); if (wpa_s->dbus_new_path) - ssid = wpa_config_add_network(wpa_s->conf); + ssid = wpa_supplicant_add_network(wpa_s); if (ssid == NULL) { wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.", __func__); @@ -1513,9 +1513,6 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, "wpa_supplicant could not add a network on this interface."); goto err; } - wpas_notify_network_added(wpa_s, ssid); - ssid->disabled = 1; - wpa_config_set_network_defaults(ssid); dbus_error_init(&error); if (!set_network_properties(wpa_s, ssid, &iter, &error)) { @@ -1580,6 +1577,27 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, /** + * wpas_dbus_handler_expect_disconnect - ExpectDisconnect + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: NULL + * + * Handler function for notifying system there will be a expected disconnect. + * This will prevent wpa_supplicant from adding blacklists upon next disconnect.. + */ +DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s = global->ifaces; + + for (; wpa_s; wpa_s = wpa_s->next) + if (wpa_s->wpa_state >= WPA_ASSOCIATED) + wpa_s->own_disconnect_req = 1; + return NULL; +} + + +/** * wpas_dbus_handler_reattach - Reattach to current AP * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface @@ -1641,8 +1659,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, const char *op; char *iface, *net_id; int id; - struct wpa_ssid *ssid; - int was_disabled; + int result; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID); @@ -1665,27 +1682,12 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, goto out; } - ssid = wpa_config_get_network(wpa_s->conf, id); - if (ssid == NULL) { + result = wpa_supplicant_remove_network(wpa_s, id); + if (result == -1) { reply = wpas_dbus_error_network_unknown(message); goto out; } - - was_disabled = ssid->disabled; - - wpas_notify_network_removed(wpa_s, ssid); - - if (ssid == wpa_s->current_ssid) - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - else if (!was_disabled && wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, - "Stop ongoing sched_scan to remove network from filters"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); - } - - if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + if (result == -2) { wpa_printf(MSG_ERROR, "%s[dbus]: error occurred when removing network %d", __func__, id); @@ -1854,7 +1856,7 @@ out: os_free(iface); return reply; #else /* IEEE8021X_EAPOL */ - wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); + wpa_printf(MSG_DEBUG, "dbus: 802.1X not included"); return wpas_dbus_error_unknown_error(message, "802.1X not included"); #endif /* IEEE8021X_EAPOL */ } @@ -2271,6 +2273,35 @@ DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, #endif /* CONFIG_TDLS */ +#ifndef CONFIG_NO_CONFIG_WRITE +/** + * wpas_dbus_handler_save_config - Save configuration to configuration file + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on Success, Otherwise errror message + * + * Handler function for "SaveConfig" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int ret; + + if (!wpa_s->conf->update_config) { + return wpas_dbus_error_unknown_error( + message, + "Not allowed to update configuration (update_config=0)"); + } + + ret = wpa_config_write(wpa_s->confname, wpa_s->conf); + if (ret) + return wpas_dbus_error_unknown_error( + message, "Failed to update configuration"); + return NULL; +} +#endif /* CONFIG_NO_CONFIG_WRITE */ + + /** * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path * @message: Pointer to incoming dbus message @@ -2338,8 +2369,9 @@ DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path( * * Getter for "Capabilities" property of an interface. */ -dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_capabilities( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_driver_capa capa; @@ -2585,12 +2617,14 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, &iter_array) || !wpa_dbus_dict_string_array_add_element( &iter_array, "infrastructure") || - !wpa_dbus_dict_string_array_add_element( - &iter_array, "ad-hoc") || + (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ad-hoc")) || (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) && !wpa_dbus_dict_string_array_add_element( &iter_array, "ap")) || (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) && + !wpa_s->conf->p2p_disabled && !wpa_dbus_dict_string_array_add_element( &iter_array, "p2p")) || !wpa_dbus_dict_end_string_array(&iter_dict, @@ -2629,8 +2663,9 @@ nomem: * * Getter for "State" property. */ -dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_state( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *str_state; @@ -2669,8 +2704,9 @@ dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, * * Getter for "scanning" property. */ -dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_scanning( + 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 scanning = wpa_s->scanning ? TRUE : FALSE; @@ -2689,8 +2725,9 @@ dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, * * Getter function for "ApScan" property. */ -dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_ap_scan( + 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 ap_scan = wpa_s->conf->ap_scan; @@ -2709,8 +2746,9 @@ dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, * * Setter function for "ApScan" property. */ -dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_ap_scan( + 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 ap_scan; @@ -2738,9 +2776,9 @@ dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, * * Getter function for "FastReauth" property. */ -dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_fast_reauth( + 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 fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE; @@ -2760,9 +2798,9 @@ dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, * * Setter function for "FastReauth" property. */ -dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_fast_reauth( + 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 fast_reauth; @@ -2786,9 +2824,9 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, * Getter for "DisconnectReason" property. The reason is negative if it is * locally generated. */ -dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_disconnect_reason( + 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->disconnect_reason; @@ -2799,6 +2837,27 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, /** + * 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 + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "AssocStatusCode" property. + */ +dbus_bool_t wpas_dbus_getter_assoc_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 status_code = wpa_s->assoc_status_code; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &status_code, 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 @@ -2807,9 +2866,9 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, * * Getter function for "BSSExpireAge" property. */ -dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_expire_age( + 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 expire_age = wpa_s->conf->bss_expiration_age; @@ -2828,9 +2887,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, * * Setter function for "BSSExpireAge" property. */ -dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_bss_expire_age( + 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 expire_age; @@ -2857,9 +2916,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, * * Getter function for "BSSExpireCount" property. */ -dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_expire_count( + 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 expire_count = wpa_s->conf->bss_expiration_scan_count; @@ -2878,9 +2937,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, * * Setter function for "BSSExpireCount" property. */ -dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_bss_expire_count( + 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 expire_count; @@ -2907,8 +2966,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, * * Getter function for "Country" property. */ -dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_country( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char country[3]; @@ -2932,8 +2992,9 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, * * Setter function for "Country" property. */ -dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_country( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *country; @@ -2970,9 +3031,9 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, * * Getter function for "ScanInterval" property. */ -dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_scan_interval( + 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 scan_interval = wpa_s->scan_interval; @@ -2991,9 +3052,9 @@ dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, * * Setter function for "ScanInterval" property. */ -dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_scan_interval( + 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 scan_interval; @@ -3020,8 +3081,9 @@ dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, * * Getter for "Ifname" property. */ -dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_ifname( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *ifname = wpa_s->ifname; @@ -3040,8 +3102,9 @@ dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, * * Getter for "Driver" property. */ -dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_driver( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *driver; @@ -3069,9 +3132,9 @@ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, * * Getter for "CurrentBSS" property. */ -dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_current_bss( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; @@ -3097,9 +3160,9 @@ dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, * * Getter for "CurrentNetwork" property. */ -dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_current_network( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; @@ -3125,9 +3188,9 @@ dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, * * Getter for "CurrentAuthMode" property. */ -dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_current_auth_mode( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *eap_mode; @@ -3143,9 +3206,11 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, "EAP-%s", eap_mode); auth_mode = eap_mode_buf; - } else { + } else if (wpa_s->current_ssid) { auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->current_ssid->proto); + } else { + auth_mode = "UNKNOWN"; } return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, @@ -3162,9 +3227,9 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, * * Getter for "BridgeIfname" property. */ -dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bridge_ifname( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *bridge_ifname = wpa_s->bridge_ifname; @@ -3175,6 +3240,30 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, /** + * wpas_dbus_getter_config_file - Get interface configuration file path + * @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 "ConfigFile" property. + */ +dbus_bool_t wpas_dbus_getter_config_file( + const struct wpa_dbus_property_desc *property_desc, + 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); +} + + +/** * wpas_dbus_getter_bsss - Get array of BSSs objects * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure @@ -3183,8 +3272,9 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, * * Getter for "BSSs" property. */ -dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bsss( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_bss *bss; @@ -3240,8 +3330,9 @@ out: * * Getter for "Networks" property. */ -dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_networks( + 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; @@ -3303,9 +3394,9 @@ out: * * Getter for "PKCS11EnginePath" property. */ -dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_pkcs11_engine_path( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *pkcs11_engine_path; @@ -3328,9 +3419,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter, * * Getter for "PKCS11ModulePath" property. */ -dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_pkcs11_module_path( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *pkcs11_module_path; @@ -3353,8 +3444,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter, * * Getter for "Blobs" property. */ -dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_blobs( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; @@ -3406,6 +3498,79 @@ dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, } +dbus_bool_t wpas_dbus_getter_iface_global( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + int ret; + char buf[250]; + char *p = buf; + + if (!property_desc->data) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Unhandled interface property %s", + property_desc->dbus_property); + return FALSE; + } + + ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf, + sizeof(buf)); + if (ret < 0) + *p = '\0'; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p, + error); +} + + +dbus_bool_t wpas_dbus_setter_iface_global( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *new_value = NULL; + char buf[250]; + size_t combined_len; + int ret; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &new_value)) + return FALSE; + + combined_len = os_strlen(property_desc->data) + os_strlen(new_value) + + 3; + if (combined_len >= sizeof(buf)) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Interface property %s value too large", + property_desc->dbus_property); + return FALSE; + } + + if (!new_value[0]) + new_value = "NULL"; + + ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data, + new_value); + if (os_snprintf_error(combined_len, ret)) { + dbus_set_error(error, WPAS_DBUS_ERROR_UNKNOWN_ERROR, + "Failed to construct new interface property %s", + property_desc->dbus_property); + return FALSE; + } + + if (wpa_config_process_global(wpa_s->conf, buf, -1)) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Failed to set interface property %s", + property_desc->dbus_property); + return FALSE; + } + + wpa_supplicant_update_config(wpa_s); + return TRUE; +} + + static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, DBusError *error, const char *func_name) { @@ -3432,8 +3597,9 @@ static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, * * Getter for "BSSID" property. */ -dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_bssid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3457,8 +3623,9 @@ dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, * * Getter for "SSID" property. */ -dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_ssid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3482,8 +3649,9 @@ dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, * * Getter for "Privacy" property. */ -dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_bss_privacy( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3508,8 +3676,9 @@ dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, * * Getter for "Mode" property. */ -dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_mode( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3549,8 +3718,9 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, * * Getter for "Level" property. */ -dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_bss_signal( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3575,8 +3745,9 @@ dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, * * Getter for "Frequency" property. */ -dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_bss_frequency( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3607,8 +3778,9 @@ static int cmp_u8s_desc(const void *a, const void *b) * * Getter for "Rates" property. */ -dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_bss_rates( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3647,9 +3819,9 @@ dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, } -static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, - struct wpa_ie_data *ie_data, - DBusError *error) +static dbus_bool_t wpas_dbus_get_bss_security_prop( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error) { DBusMessageIter iter_dict, variant_iter; const char *group; @@ -3780,8 +3952,9 @@ nomem: * * Getter for "WPA" property. */ -dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_wpa( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3800,7 +3973,7 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, return FALSE; } - return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); + return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error); } @@ -3813,8 +3986,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, * * Getter for "RSN" property. */ -dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_rsn( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3833,7 +4007,7 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, return FALSE; } - return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); + return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error); } @@ -3846,8 +4020,9 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, * * Getter for "WPS" property. */ -dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_wps( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3902,8 +4077,9 @@ nomem: * * Getter for "IEs" property. */ -dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_ies( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3927,8 +4103,9 @@ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, * * Getter for BSS age */ -dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_bss_age( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; @@ -3956,8 +4133,9 @@ dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error, * * Getter for "enabled" property of a configured network. */ -dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_enabled( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; @@ -3976,8 +4154,9 @@ dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, * * Setter for "Enabled" property of a configured network. */ -dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_enabled( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; struct wpa_supplicant *wpa_s; @@ -4009,9 +4188,9 @@ dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, * * Getter for "Properties" property of a configured network. */ -dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_network_properties( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; DBusMessageIter variant_iter, dict_iter; @@ -4071,9 +4250,9 @@ out: * * Setter for "Properties" property of a configured network. */ -dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_network_properties( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; struct wpa_ssid *ssid = net->ssid; @@ -4211,3 +4390,147 @@ out: } #endif /* CONFIG_AP */ + + +DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 *ielems; + int len; + struct ieee802_11_elems elems; + dbus_int32_t frame_id; + DBusMessageIter iter, array; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &ielems, &len); + if (!ielems || len == 0) { + return dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, "Invalid value"); + } + + if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Parse error"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + if (!wpa_s->vendor_elem[frame_id]) { + wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len); + wpas_vendor_elem_update(wpa_s); + return NULL; + } + + if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Resize error"); + } + + wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len); + wpas_vendor_elem_update(wpa_s); + return NULL; +} + + +DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply; + DBusMessageIter iter, array_iter; + dbus_int32_t frame_id; + const u8 *elem; + size_t elem_len; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + if (!wpa_s->vendor_elem[frame_id]) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "ID value does not exist"); + } + + reply = dbus_message_new_method_return(message); + if (!reply) + return wpas_dbus_error_no_memory(message); + + dbus_message_iter_init_append(reply, &iter); + + elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]); + elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array_iter) || + !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, + &elem, elem_len) || + !dbus_message_iter_close_container(&iter, &array_iter)) { + dbus_message_unref(reply); + reply = wpas_dbus_error_no_memory(message); + } + + return reply; +} + + +DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 *ielems; + int len; + struct ieee802_11_elems elems; + DBusMessageIter iter, array; + dbus_int32_t frame_id; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &ielems, &len); + if (!ielems || len == 0) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid value"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + + if (len == 1 && *ielems == '*') { + wpabuf_free(wpa_s->vendor_elem[frame_id]); + wpa_s->vendor_elem[frame_id] = NULL; + wpas_vendor_elem_update(wpa_s); + return NULL; + } + + if (!wpa_s->vendor_elem[frame_id]) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "ID value does not exist"); + } + + if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Parse error"); + } + + if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0) + return NULL; + + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Not found"); +} diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index 50f72ec..1d6235d 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -10,6 +10,8 @@ #ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H #define CTRL_IFACE_DBUS_NEW_HANDLERS_H +#include "dbus_new_helpers.h" + struct network_handler_args { struct wpa_supplicant *wpa_s; struct wpa_ssid *ssid; @@ -50,39 +52,20 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, struct wpa_global *global); -dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter, - DBusError *error, - void *user_data); +DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message, + struct wpa_global *global); + +DECLARE_ACCESSOR(wpas_dbus_getter_debug_level); +DECLARE_ACCESSOR(wpas_dbus_getter_debug_timestamp); +DECLARE_ACCESSOR(wpas_dbus_getter_debug_show_keys); +DECLARE_ACCESSOR(wpas_dbus_setter_debug_level); +DECLARE_ACCESSOR(wpas_dbus_setter_debug_timestamp); +DECLARE_ACCESSOR(wpas_dbus_setter_debug_show_keys); +DECLARE_ACCESSOR(wpas_dbus_getter_interfaces); +DECLARE_ACCESSOR(wpas_dbus_getter_eap_methods); +DECLARE_ACCESSOR(wpas_dbus_getter_global_capabilities); +DECLARE_ACCESSOR(wpas_dbus_getter_iface_global); +DECLARE_ACCESSOR(wpas_dbus_setter_iface_global); DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, struct wpa_supplicant *wpa_s); @@ -146,150 +129,52 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, struct wpa_supplicant *wpa_s); -dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data); +DECLARE_ACCESSOR(wpas_dbus_getter_capabilities); +DECLARE_ACCESSOR(wpas_dbus_getter_state); +DECLARE_ACCESSOR(wpas_dbus_getter_scanning); +DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan); +DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan); +DECLARE_ACCESSOR(wpas_dbus_getter_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_assoc_status_code); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age); +DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count); +DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_count); +DECLARE_ACCESSOR(wpas_dbus_getter_country); +DECLARE_ACCESSOR(wpas_dbus_setter_country); +DECLARE_ACCESSOR(wpas_dbus_getter_scan_interval); +DECLARE_ACCESSOR(wpas_dbus_setter_scan_interval); +DECLARE_ACCESSOR(wpas_dbus_getter_ifname); +DECLARE_ACCESSOR(wpas_dbus_getter_driver); +DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname); +DECLARE_ACCESSOR(wpas_dbus_getter_config_file); +DECLARE_ACCESSOR(wpas_dbus_getter_current_bss); +DECLARE_ACCESSOR(wpas_dbus_getter_current_network); +DECLARE_ACCESSOR(wpas_dbus_getter_current_auth_mode); +DECLARE_ACCESSOR(wpas_dbus_getter_bsss); +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_bss_bssid); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_mode); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_signal); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_frequency); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_rates); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_wpa); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_rsn); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_age); +DECLARE_ACCESSOR(wpas_dbus_getter_enabled); +DECLARE_ACCESSOR(wpas_dbus_setter_enabled); +DECLARE_ACCESSOR(wpas_dbus_getter_network_properties); +DECLARE_ACCESSOR(wpas_dbus_setter_network_properties); DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, struct wpa_supplicant *wpa_s); @@ -297,20 +182,10 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message, struct wpa_supplicant *wpa_s); -dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter, - DBusError *error, - void *user_data); +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); DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, struct wpa_supplicant *wpa_s); @@ -321,6 +196,16 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, + struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message, + struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_vendor_elem_remove( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message, + struct wpa_supplicant *wpa_s); + DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, const char *arg); DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 67c079e..73b9e20 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -364,13 +364,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, - NULL, 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)) + } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0, + 0)) goto inv_args; out: @@ -582,7 +583,7 @@ 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, -1, 0, 0, 0); + go_intent, freq, 0, -1, 0, 0, 0, 0, NULL, 0); if (new_pin >= 0) { char npin[9]; @@ -733,8 +734,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, if (ssid == NULL || ssid->disabled != 2) goto err; - if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) < - 0) { + if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0, + 0) < 0) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); @@ -807,9 +808,9 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message, * P2P Device property accessor methods. */ -dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_device_config( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, dict_iter; @@ -916,9 +917,9 @@ err_no_mem: } -dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_p2p_device_config( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, iter_dict; @@ -944,7 +945,8 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, if (os_strcmp(entry.key, "DeviceName") == 0) { char *devname; - if (entry.type != DBUS_TYPE_STRING) + if (entry.type != DBUS_TYPE_STRING || + os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN) goto error; devname = os_strdup(entry.str_value); @@ -1087,8 +1089,9 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peers( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct p2p_data *p2p = wpa_s->global->p2p; @@ -1201,8 +1204,9 @@ static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s) } -dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_role( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char *str; @@ -1224,8 +1228,9 @@ dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, } -dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; @@ -1243,8 +1248,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, } -dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peergo( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; @@ -1271,9 +1277,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, * Peer object properties accessor methods */ -dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_device_name( + 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; @@ -1309,9 +1315,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer( + 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; @@ -1346,9 +1352,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_modelname( + 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; @@ -1383,9 +1389,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber( + 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; @@ -1420,9 +1426,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber( + 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; @@ -1458,6 +1464,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter, dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( + const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; @@ -1483,9 +1490,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( } -dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_config_method( + 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; @@ -1508,9 +1515,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_level( + 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; @@ -1533,9 +1540,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability( + 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; @@ -1558,9 +1565,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability( + 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; @@ -1584,6 +1591,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( + const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; @@ -1649,9 +1657,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( } -dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT]; unsigned int i, num = 0; @@ -1684,8 +1692,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_ies( + 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; @@ -1709,9 +1718,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_device_address( + 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; @@ -1774,9 +1783,9 @@ out_of_memory: } -dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_peer_groups( + 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; @@ -1842,9 +1851,9 @@ out: * * Getter for "PersistentGroups" property. */ -dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_persistent_groups( + 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; @@ -1904,16 +1913,16 @@ out: * * Getter for "Properties" property of a persistent group. */ -dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_persistent_group_properties( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; /* Leveraging the fact that persistent group object is still * represented in same manner as network within. */ - return wpas_dbus_getter_network_properties(iter, error, net); + return wpas_dbus_getter_network_properties(property_desc, iter, error, net); } @@ -1927,9 +1936,9 @@ dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, * * Setter for "Properties" property of a persistent group. */ -dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_persistent_group_properties( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; struct wpa_ssid *ssid = net->ssid; @@ -2142,9 +2151,9 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( * Group object properties accessor methods */ -dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_members( + 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; @@ -2211,8 +2220,9 @@ out_of_memory: } -dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_ssid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; @@ -2224,9 +2234,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_bssid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u8 role = wpas_get_p2p_role(wpa_s); @@ -2248,9 +2258,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_frequency( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u16 op_freq; @@ -2271,9 +2281,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_passphrase( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char *p_pass; @@ -2292,8 +2302,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_psk( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u8 *p_psk = NULL; @@ -2313,9 +2324,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext( + 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; @@ -2348,9 +2359,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, iter_dict, array_iter, sub; @@ -2876,8 +2887,9 @@ DBusMessage * wpas_dbus_handler_p2p_serv_disc_external( #ifdef CONFIG_WIFI_DISPLAY -dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_getter_global_wfd_ies( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; struct wpabuf *ie; @@ -2898,8 +2910,9 @@ dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter, } -dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter, - DBusError *error, void *user_data) +dbus_bool_t wpas_dbus_setter_global_wfd_ies( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; DBusMessageIter variant, array; diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h index 2aecbbe..c4c0261 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h @@ -89,139 +89,50 @@ DBusMessage *wpas_dbus_handler_p2p_serv_disc_external( /* * P2P Device property accessor methods. */ -dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, - DBusError *error, - void *user_data); +DECLARE_ACCESSOR(wpas_dbus_setter_p2p_device_config); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_device_config); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peers); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_role); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peergo); /* * P2P Peer properties. */ - -dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( - DBusMessageIter *iter, DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( - DBusMessageIter *iter, DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter, - DBusError *error, - void *user_data); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_name); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_manufacturer); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelname); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelnumber); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_serialnumber); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_primary_device_type); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_config_method); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_level); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_capability); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_group_capability); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_secondary_device_types); +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); /* * P2P Group properties */ - -dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, - DBusError *error, - void *user_data); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_members); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_ssid); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_bssid); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_frequency); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_passphrase); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_psk); +DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_vendor_ext); +DECLARE_ACCESSOR(wpas_dbus_setter_p2p_group_vendor_ext); /* * P2P Persistent Groups and properties */ - -dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, - DBusError *error, void *user_data); - -dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, - DBusError *error, - void *user_data); +DECLARE_ACCESSOR(wpas_dbus_getter_persistent_groups); +DECLARE_ACCESSOR(wpas_dbus_getter_persistent_group_properties); +DECLARE_ACCESSOR(wpas_dbus_setter_persistent_group_properties); DBusMessage * wpas_dbus_handler_add_persistent_group( DBusMessage *message, struct wpa_supplicant *wpa_s); @@ -233,15 +144,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( DBusMessage *message, struct wpa_supplicant *wpa_s); #ifdef CONFIG_WIFI_DISPLAY - -dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter, - DBusError *error, - void *user_data); - -dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter, - DBusError *error, - void *user_data); - +DECLARE_ACCESSOR(wpas_dbus_getter_global_wfd_ies); +DECLARE_ACCESSOR(wpas_dbus_setter_global_wfd_ies); #endif /* CONFIG_WIFI_DISPLAY */ #endif /* DBUS_NEW_HANDLERS_P2P_H */ diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c index b2251ba..f16e229 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c @@ -325,7 +325,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, * @wpa_s: %wpa_supplicant data structure * Returns: NULL on success or DBus error on failure * - * Handler for "Cancel" method call. Returns NULL if WPS cancel successfull + * Handler for "Cancel" method call. Returns NULL if WPS cancel successful * or DBus error on WPS cancel failure */ DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message, @@ -349,9 +349,9 @@ DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message, * true if wps_cred_processing configuration field is not equal to 1 or false * if otherwise. */ -dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_process_credentials( + 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 process = wpa_s->conf->wps_cred_processing != 1; @@ -371,9 +371,9 @@ dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, * Setter for "ProcessCredentials" property. Sets credentials_processed on 2 * if boolean argument is true or on 1 if otherwise. */ -dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_process_credentials( + 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 process_credentials, old_pc; @@ -407,9 +407,9 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, * Getter for "ConfigMethods" property. Returned boolean will be true if * providing the relevant string worked, or false otherwise. */ -dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_getter_config_methods( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char *methods = wpa_s->conf->config_methods; @@ -431,9 +431,9 @@ dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter, * Setter for "ConfigMethods" property. Sets the methods string, apply such * change and returns true on success. Returns false otherwise. */ -dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter, - DBusError *error, - void *user_data) +dbus_bool_t wpas_dbus_setter_config_methods( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char *methods, *new_methods; diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c index 45623f3..0115e32 100644 --- a/wpa_supplicant/dbus/dbus_new_helpers.c +++ b/wpa_supplicant/dbus/dbus_new_helpers.c @@ -46,7 +46,7 @@ static dbus_bool_t fill_dict_with_properties( goto error; /* An error getting a property fails the request entirely */ - if (!dsc->getter(&entry_iter, error, user_data)) { + if (!dsc->getter(dsc, &entry_iter, error, user_data)) { wpa_printf(MSG_INFO, "dbus: %s dbus_interface=%s dbus_property=%s getter failed", __func__, dsc->dbus_interface, @@ -176,7 +176,7 @@ static DBusMessage * properties_get(DBusMessage *message, dbus_message_iter_init_append(reply, &iter); dbus_error_init(&error); - if (dsc->getter(&iter, &error, user_data) == FALSE) { + if (dsc->getter(dsc, &iter, &error, user_data) == FALSE) { dbus_message_unref(reply); reply = wpas_dbus_reply_new_from_error( message, &error, DBUS_ERROR_FAILED, @@ -213,7 +213,7 @@ static DBusMessage * properties_set(DBusMessage *message, /* Iter will now point to the property's new value */ dbus_error_init(&error); - if (dsc->setter(&iter, &error, user_data) == TRUE) { + if (dsc->setter(dsc, &iter, &error, user_data) == TRUE) { /* Success */ reply = dbus_message_new_method_return(message); } else { @@ -627,7 +627,8 @@ static dbus_bool_t put_changed_properties( return FALSE; dbus_error_init(&error); - if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) { + if (!dsc->getter(dsc, &entry_iter, &error, obj_dsc->user_data)) + { if (dbus_error_is_set(&error)) { wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value of property %s: (%s) %s", diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h index 6e2c1f1..7b63b28 100644 --- a/wpa_supplicant/dbus/dbus_new_helpers.h +++ b/wpa_supplicant/dbus/dbus_new_helpers.h @@ -16,9 +16,13 @@ typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message, void *user_data); typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg); -typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter, - DBusError *error, - void *user_data); +struct wpa_dbus_property_desc; +typedef dbus_bool_t (*WPADBusPropertyAccessor)( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data); +#define DECLARE_ACCESSOR(f) \ +dbus_bool_t f(const struct wpa_dbus_property_desc *property_desc, \ + DBusMessageIter *iter, DBusError *error, void *user_data) struct wpa_dbus_object_desc { DBusConnection *connection; @@ -89,6 +93,8 @@ struct wpa_dbus_property_desc { WPADBusPropertyAccessor getter; /* property setter function */ WPADBusPropertyAccessor setter; + /* other data */ + const char *data; }; diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c index fba57e6..aee105b 100644 --- a/wpa_supplicant/dbus/dbus_new_introspect.c +++ b/wpa_supplicant/dbus/dbus_new_introspect.c @@ -38,7 +38,7 @@ static struct interfaces * add_interface(struct dl_list *list, if (!iface) return NULL; iface->dbus_interface = os_strdup(dbus_interface); - iface->xml = wpabuf_alloc(6000); + iface->xml = wpabuf_alloc(15000); if (iface->dbus_interface == NULL || iface->xml == NULL) { os_free(iface->dbus_interface); wpabuf_free(iface->xml); @@ -257,7 +257,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message, DBusMessage *reply; struct wpabuf *xml; - xml = wpabuf_alloc(15000); + xml = wpabuf_alloc(20000); if (xml == NULL) return NULL; diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c index e8f62ef..e540832 100644 --- a/wpa_supplicant/dbus/dbus_old_handlers.c +++ b/wpa_supplicant/dbus/dbus_old_handlers.c @@ -717,16 +717,13 @@ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; if (wpa_s->dbus_path) - ssid = wpa_config_add_network(wpa_s->conf); + 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; } - wpas_notify_network_added(wpa_s, ssid); - ssid->disabled = 1; - wpa_config_set_network_defaults(ssid); /* Construct the object path for this network. */ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, @@ -758,7 +755,7 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, const char *op; char *iface = NULL, *net_id = NULL; int id; - struct wpa_ssid *ssid; + int result; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, @@ -781,19 +778,12 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, } id = strtoul(net_id, NULL, 10); - ssid = wpa_config_get_network(wpa_s->conf, id); - if (ssid == NULL) { + result = wpa_supplicant_remove_network(wpa_s, id); + if (result == -1) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } - - wpas_notify_network_removed(wpa_s, ssid); - - if (ssid == wpa_s->current_ssid) - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - - if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + if (result == -2) { reply = dbus_message_new_error( message, WPAS_ERROR_REMOVE_NETWORK_ERROR, "error removing the specified on this interface."); @@ -1069,8 +1059,7 @@ out: DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s) { - wpa_s->disconnected = 1; - wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + wpas_request_disconnection(wpa_s); return wpas_dbus_new_success_reply(message); } diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 01a8c2c..1d05198 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -31,6 +31,9 @@ CONFIG_DRIVER_WEXT=y # Driver interface for Linux drivers using the nl80211 kernel interface CONFIG_DRIVER_NL80211=y +# QCA vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_QCA=y + # driver_nl80211.c requires libnl. If you are compiling it yourself # you may need to point hostapd to your version of libnl. # @@ -267,6 +270,9 @@ CONFIG_BACKEND=file # 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 @@ -276,6 +282,12 @@ CONFIG_BACKEND=file # none = Empty template #CONFIG_L2_PACKET=linux +# 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 + # PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) CONFIG_PEERKEY=y @@ -455,6 +467,9 @@ CONFIG_PEERKEY=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 @@ -504,3 +519,32 @@ CONFIG_PEERKEY=y # OS X builds. This is only for building eapol_test. #CONFIG_OSX=y + +# Automatic Channel Selection +# This will allow wpa_supplicant to pick the channel automatically when channel +# is set to "0". +# +# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative +# to "channel=0". This would enable us to eventually add other ACS algorithms in +# similar way. +# +# Automatic selection is currently only done through initialization, later on +# we hope to do background checks to keep us moving to more ideal channels as +# time goes by. ACS is currently only supported through the nl80211 driver and +# your driver must have survey dump capability that is filled by the driver +# during scanning. +# +# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with +# a newly to create wpa_supplicant.conf variable acs_num_scans. +# +# Supported ACS drivers: +# * ath9k +# * ath5k +# * ath10k +# +# For more details refer to: +# http://wireless.kernel.org/en/users/Documentation/acs +#CONFIG_ACS=y + +# Support Multi Band Operation +#CONFIG_MBO=y diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml index e9af6d9..3f22413 100644 --- a/wpa_supplicant/doc/docbook/eapol_test.sgml +++ b/wpa_supplicant/doc/docbook/eapol_test.sgml @@ -194,7 +194,7 @@ eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1 </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml index afb8c3b..13c9f45 100644 --- a/wpa_supplicant/doc/docbook/wpa_background.sgml +++ b/wpa_supplicant/doc/docbook/wpa_background.sgml @@ -90,7 +90,7 @@ <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml index 47947c1..15400f0 100644 --- a/wpa_supplicant/doc/docbook/wpa_cli.sgml +++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml @@ -345,7 +345,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml index 5f7b49d..352d3d2 100644 --- a/wpa_supplicant/doc/docbook/wpa_gui.sgml +++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml @@ -91,7 +91,7 @@ </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml index b381e40..faf1f27 100644 --- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml +++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml @@ -62,7 +62,7 @@ </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml index d13a5db..403c9b2 100644 --- a/wpa_supplicant/doc/docbook/wpa_priv.sgml +++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml @@ -137,7 +137,7 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml index 46c21b5..11e0e90 100644 --- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml @@ -377,13 +377,6 @@ </varlistentry> <varlistentry> - <term>-t</term> - <listitem> - <para>Include timestamp in debug messages.</para> - </listitem> - </varlistentry> - - <varlistentry> <term>-h</term> <listitem> <para>Help. Show a usage message.</para> @@ -736,7 +729,7 @@ fi </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2015, + <para>wpa_supplicant is copyright (c) 2003-2016, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 73768c7..220b7ba 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -100,12 +100,10 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s, } static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params, - u32 interval) + struct wpa_driver_scan_params *params) { if (wpa_s->driver->sched_scan) - return wpa_s->driver->sched_scan(wpa_s->drv_priv, - params, interval); + return wpa_s->driver->sched_scan(wpa_s->drv_priv, params); return -1; } @@ -160,6 +158,15 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, return -1; } +static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s, + const u8 *addr, int idx, u8 *seq) +{ + if (wpa_s->driver->get_seqnum) + return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv, + addr, idx, seq); + return -1; +} + static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s, const u8 *addr, int reason_code) { @@ -292,7 +299,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s, if (wpa_s->driver->send_mlme) return wpa_s->driver->send_mlme(wpa_s->drv_priv, data, data_len, noack, - freq); + freq, NULL, 0); return -1; } @@ -401,7 +408,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s, if (wpa_s->driver->if_add) return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname, addr, bss_ctx, NULL, force_ifname, - if_addr, bridge, 0); + if_addr, bridge, 0, 0); return -1; } @@ -726,12 +733,11 @@ static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s, } static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s, - const u8 *cs, size_t cs_len) + u64 cs) { if (!wpa_s->driver->set_current_cipher_suite) return -1; - return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs, - cs_len); + return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs); } static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s, @@ -912,4 +918,62 @@ 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) +{ + if (!wpa_s->driver->abort_scan) + return -1; + return wpa_s->driver->abort_scan(wpa_s->drv_priv); +} + +static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s, + u32 filters) +{ + if (!wpa_s->driver->configure_data_frame_filters) + return -1; + return wpa_s->driver->configure_data_frame_filters(wpa_s->drv_priv, + filters); +} + +static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s, + enum wpa_driver_if_type type) +{ + if (!wpa_s->driver->get_ext_capab) + return -1; + return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type, + &wpa_s->extended_capa, + &wpa_s->extended_capa_mask, + &wpa_s->extended_capa_len); +} + +static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s, + unsigned int channel, + unsigned int period, + unsigned int interval, + unsigned int count, + const u8 *device_types, + size_t dev_types_len, + const u8 *ies, size_t ies_len) +{ + if (!wpa_s->driver->p2p_lo_start) + return -1; + return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period, + interval, count, device_types, + dev_types_len, ies, ies_len); +} + +static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->p2p_lo_stop) + return -1; + return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv); +} + +static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t len) +{ + if (!wpa_s->driver->set_default_scan_ies) + return -1; + return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index dce7d1f..6548bd1 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -14,6 +14,7 @@ #include "common.h" #include "utils/ext_password.h" +#include "common/version.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "eap_peer/eap.h" @@ -192,7 +193,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, return; } - radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); + radius_msg_make_authenticator(msg); hdr = (const struct eap_hdr *) eap; pos = (const u8 *) (hdr + 1); @@ -257,6 +258,13 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, goto fail; } + if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_SERVICE_TYPE) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE, + RADIUS_SERVICE_TYPE_FRAMED)) { + printf("Could not add Service-Type\n"); + goto fail; + } + os_snprintf(buf, sizeof(buf), "%s", e->connect_info); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, @@ -1239,7 +1247,7 @@ static void eapol_test_terminate(int sig, void *signal_ctx) static void usage(void) { printf("usage:\n" - "eapol_test [-enWS] -c<conf> [-a<AS IP>] [-p<AS port>] " + "eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] " "[-s<AS secret>]\\\n" " [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n" " [-M<client MAC address>] [-o<server cert file] \\\n" @@ -1264,6 +1272,7 @@ static void usage(void) " -W = wait for a control interface monitor before starting\n" " -S = save configuration after authentication\n" " -n = no MPPE keys expected\n" + " -v = show version\n" " -t<timeout> = sets timeout in seconds (default: 30 s)\n" " -C<Connect-Info> = RADIUS Connect-Info (default: " "CONNECT 11Mbps 802.11b)\n" @@ -1317,7 +1326,7 @@ int main(int argc, char *argv[]) wpa_debug_show_keys = 1; for (;;) { - c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:W"); + c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW"); if (c < 0) break; switch (c) { @@ -1383,6 +1392,9 @@ int main(int argc, char *argv[]) ctrl_iface = optarg; eapol_test.ctrl_iface = 1; break; + case 'v': + printf("eapol_test v" VERSION_STR "\n"); + return 0; case 'W': wait_for_monitor++; break; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 3af1c7d..abe3b47 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -72,6 +72,7 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, } +#ifndef CONFIG_NO_SCAN_PROCESSING /** * wpas_reenabled_network_time - Time until first network is re-enabled * @wpa_s: Pointer to wpa_supplicant data @@ -107,6 +108,7 @@ static int wpas_reenabled_network_time(struct wpa_supplicant *wpa_s) return res; } +#endif /* CONFIG_NO_SCAN_PROCESSING */ void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx) @@ -279,6 +281,11 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpa_supplicant_ap_deinit(wpa_s); #endif /* CONFIG_AP */ +#ifdef CONFIG_HS20 + /* Clear possibly configured frame filters */ + wpa_drv_configure_frame_filters(wpa_s, 0); +#endif /* CONFIG_HS20 */ + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) return; @@ -303,6 +310,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpa_s->key_mgmt = 0; wpas_rrm_reset(wpa_s); + wpa_s->wnmsleep_used = 0; } @@ -564,11 +572,36 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, 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"); + break; + } +#ifdef CONFIG_MBO + if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && + wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) && + wpas_get_ssid_pmf(wpa_s, ssid) != + NO_MGMT_FRAME_PROTECTION) { + 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"); 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"); + return 0; + } +#endif /* CONFIG_IEEE80211W */ + wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { proto_match++; @@ -806,10 +839,10 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num) } -static 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) +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) { u8 wpa_ie_len, rsn_ie_len; int wpa; @@ -817,6 +850,9 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, const u8 *ie; struct wpa_ssid *ssid; int osen; +#ifdef CONFIG_MBO + const u8 *assoc_disallow; +#endif /* CONFIG_MBO */ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); wpa_ie_len = ie ? ie[1] : 0; @@ -978,8 +1014,16 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } - if (!bss_is_ess(bss)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network"); + 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"); + 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)); continue; } @@ -989,6 +1033,14 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, 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)"); + continue; + } +#endif /* CONFIG_MESH */ + if (!rate_match(wpa_s, bss)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do " "not match"); @@ -1048,6 +1100,29 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, (unsigned int) diff.usec); continue; } +#ifdef CONFIG_MBO +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_assoc_disallow) + goto skip_assoc_disallow; +#endif /* CONFIG_TESTING_OPTIONS */ + assoc_disallow = wpas_mbo_get_bss_attr( + bss, MBO_ATTR_ID_ASSOC_DISALLOW); + if (assoc_disallow && assoc_disallow[1] >= 1) { + 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"); + continue; + } +#ifdef CONFIG_TESTING_OPTIONS + skip_assoc_disallow: +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_MBO */ /* Matching configuration found */ return ssid; @@ -1301,6 +1376,7 @@ 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 to_5ghz; #endif /* CONFIG_NO_ROAMING */ if (wpa_s->reassociate) @@ -1356,7 +1432,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, return 1; } - if (current_bss->level < 0 && current_bss->level > selected->level) { + to_5ghz = selected->freq > 4000 && current_bss->freq < 4000; + + if (current_bss->level < 0 && + current_bss->level > selected->level + to_5ghz * 2) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better " "signal level"); return 0; @@ -1375,6 +1454,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, else min_diff = 5; } + if (to_5ghz) { + /* Make it easier to move to 5 GHz band */ + if (min_diff > 2) + min_diff -= 2; + 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"); @@ -1417,6 +1503,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return -1; if (!own_request) return -1; + if (data && data->scan_info.external_scan) + return -1; wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try " "scanning again"); wpa_supplicant_req_new_scan(wpa_s, 1, 0); @@ -1441,7 +1529,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_RANDOM_POOL */ if (own_request && wpa_s->scan_res_handler && - (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) { + !(data && data->scan_info.external_scan)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); @@ -1462,9 +1550,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, } wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", - wpa_s->own_scan_running, wpa_s->radio->external_scan_running); + wpa_s->own_scan_running, + data ? data->scan_info.external_scan : 0); if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && - wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { + wpa_s->manual_scan_use_id && wpa_s->own_scan_running && + own_request && !(data && data->scan_info.external_scan)) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", wpa_s->manual_scan_id); wpa_s->manual_scan_use_id = 0; @@ -1475,7 +1565,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_notify_scan_done(wpa_s, 1); - if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) { + if (data && data->scan_info.external_scan) { wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection"); wpa_scan_results_free(scan_res); return 0; @@ -1504,9 +1594,13 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_wps_update_ap_info(wpa_s, scan_res); + if (wpa_s->wpa_state >= WPA_AUTHENTICATING && + wpa_s->wpa_state < WPA_COMPLETED) + goto scan_work_done; + wpa_scan_results_free(scan_res); - if (wpa_s->scan_work) { + if (own_request && wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); @@ -1516,7 +1610,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, scan_work_done: wpa_scan_results_free(scan_res); - if (wpa_s->scan_work) { + if (own_request && wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); @@ -1547,6 +1641,14 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, selected = wpa_supplicant_pick_network(wpa_s, &ssid); +#ifdef CONFIG_MESH + if (wpa_s->ifmsh) { + wpa_msg(wpa_s, MSG_INFO, + "Avoiding join because we already joined a mesh group"); + return 0; + } +#endif /* CONFIG_MESH */ + if (selected) { int skip; skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid); @@ -1556,6 +1658,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; } + if (ssid != wpa_s->current_ssid && + wpa_s->wpa_state >= WPA_AUTHENTICATING) { + wpa_s->own_disconnect_req = 1; + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } + if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed"); return -1; @@ -1568,13 +1677,6 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, */ return 1; } else { -#ifdef CONFIG_MESH - if (wpa_s->ifmsh) { - wpa_msg(wpa_s, MSG_INFO, - "Avoiding join because we already joined a mesh group"); - return 0; - } -#endif /* CONFIG_MESH */ wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found"); ssid = wpa_supplicant_pick_new_network(wpa_s); if (ssid) { @@ -1830,6 +1932,50 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_FST +static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s, + const u8 *ie, size_t ie_len) +{ + struct mb_ies_info mb_ies; + + if (!ie || !ie_len || !wpa_s->fst) + return -ENOENT; + + os_memset(&mb_ies, 0, sizeof(mb_ies)); + + while (ie_len >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) { + size_t len; + + len = 2 + ie[1]; + if (len > ie_len) { + wpa_hexdump(MSG_DEBUG, "FST: Truncated IE found", + ie, ie_len); + break; + } + + if (ie[0] == WLAN_EID_MULTI_BAND) { + wpa_printf(MSG_DEBUG, "MB IE of %u bytes found", + (unsigned int) len); + mb_ies.ies[mb_ies.nof_ies].ie = ie + 2; + mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2; + mb_ies.nof_ies++; + } + + ie_len -= len; + ie += len; + } + + if (mb_ies.nof_ies > 0) { + wpabuf_free(wpa_s->received_mb_ies); + wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies); + return 0; + } + + return -ENOENT; +} +#endif /* CONFIG_FST */ + + static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -1880,6 +2026,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, } if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || + (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 && + (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) || (p[0] == WLAN_EID_RSN && p[1] >= 2)) { if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) break; @@ -2012,19 +2160,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, if (wpa_found || rsn_found) wpa_s->ap_ies_from_associnfo = 1; -#ifdef CONFIG_FST - wpabuf_free(wpa_s->received_mb_ies); - wpa_s->received_mb_ies = NULL; - if (wpa_s->fst) { - struct mb_ies_info mb_ies; - - wpa_printf(MSG_DEBUG, "Looking for MB IE"); - if (!mb_ies_info_by_ies(&mb_ies, data->assoc_info.resp_ies, - data->assoc_info.resp_ies_len)) - wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies); - } -#endif /* CONFIG_FST */ - if (wpa_s->assoc_freq && data->assoc_info.freq && wpa_s->assoc_freq != data->assoc_info.freq) { wpa_printf(MSG_DEBUG, "Operating frequency changed from " @@ -2063,11 +2198,50 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s) } +static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ +#ifdef CONFIG_FST + struct assoc_info *ai = data ? &data->assoc_info : NULL; + struct wpa_bss *bss = wpa_s->current_bss; + const u8 *ieprb, *iebcn; + + wpabuf_free(wpa_s->received_mb_ies); + wpa_s->received_mb_ies = NULL; + + if (ai && + !wpas_fst_update_mbie(wpa_s, ai->resp_ies, ai->resp_ies_len)) { + wpa_printf(MSG_DEBUG, + "FST: MB IEs updated from Association Response frame"); + return; + } + + if (ai && + !wpas_fst_update_mbie(wpa_s, ai->beacon_ies, ai->beacon_ies_len)) { + wpa_printf(MSG_DEBUG, + "FST: MB IEs updated from association event Beacon IEs"); + return; + } + + if (!bss) + return; + + ieprb = (const u8 *) (bss + 1); + iebcn = ieprb + bss->ie_len; + + if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len)) + wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss IE"); + else if (!wpas_fst_update_mbie(wpa_s, iebcn, bss->beacon_ie_len)) + wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss beacon IE"); +#endif /* CONFIG_FST */ +} + + static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { u8 bssid[ETH_ALEN]; - int ft_completed; + int ft_completed, already_authorized; int new_bss = 0; #ifdef CONFIG_AP @@ -2123,6 +2297,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, "WPA/RSN IEs not updated"); } + wpas_fst_update_mb_assoc(wpa_s, data); + #ifdef CONFIG_SME os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN); wpa_s->sme.prev_bssid_set = 1; @@ -2141,6 +2317,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (wpa_s->l2) l2_packet_notify_auth_start(wpa_s->l2); + already_authorized = data && data->assoc_info.authorized; + /* * Set portEnabled first to FALSE in order to get EAP state machine out * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE @@ -2149,11 +2327,12 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, * AUTHENTICATED without ever giving chance to EAP state machine to * reset the state. */ - if (!ft_completed) { + if (!ft_completed && !already_authorized) { 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) || ft_completed || + already_authorized) eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); /* 802.1X::portControl = Auto */ eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); @@ -2245,7 +2424,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s->key_mgmt != WPA_KEY_MGMT_NONE && wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE && wpa_s->ibss_rsn == NULL) { - wpa_s->ibss_rsn = ibss_rsn_init(wpa_s); + wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid); if (!wpa_s->ibss_rsn) { wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN"); wpa_supplicant_deauthenticate( @@ -2339,6 +2518,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, struct wpa_bss *fast_reconnect = NULL; struct wpa_ssid *fast_reconnect_ssid = NULL; struct wpa_ssid *last_ssid; + struct wpa_bss *curr = NULL; authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING; os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN); @@ -2354,6 +2534,19 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, return; } + if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING && + reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY && + locally_generated) + /* + * Remove the inactive AP (which is probably out of range) from + * the BSS list after marking disassociation. In particular + * mac80211-based drivers use the + * WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in + * locally generated disconnection events for cases where the + * AP does not reply anymore. + */ + curr = wpa_s->current_bss; + if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) { wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " "pre-shared key may be incorrect"); @@ -2364,7 +2557,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, if (!wpa_s->disconnected && (!wpa_s->auto_reconnect_disabled || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS || - wpas_wps_searching(wpa_s))) { + wpas_wps_searching(wpa_s) || + wpas_wps_reenable_networks_pending(wpa_s))) { wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to " "reconnect (wps=%d/%d wpa_state=%d)", wpa_s->key_mgmt == WPA_KEY_MGMT_WPS, @@ -2414,6 +2608,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, last_ssid = wpa_s->current_ssid; wpa_supplicant_mark_disassoc(wpa_s); + if (curr) + wpa_bss_remove(wpa_s, curr, "Connection to AP lost"); + if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid); wpa_s->current_ssid = last_ssid; @@ -2424,7 +2621,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, !disallowed_bssid(wpa_s, fast_reconnect->bssid) && !disallowed_ssid(wpa_s, fast_reconnect->ssid, fast_reconnect->ssid_len) && - !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) { + !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) && + !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) { #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, @@ -2622,6 +2820,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ +#ifdef CONFIG_MATCH_IFACE + if (wpa_s->matched) { + wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0); + break; + } +#endif /* CONFIG_MATCH_IFACE */ + #ifdef CONFIG_TERMINATE_ONLASTIF /* check if last interface */ if (!any_interfaces(wpa_s->global->ifaces)) @@ -3007,7 +3212,16 @@ static void wpa_supplicant_update_channel_list( { struct wpa_supplicant *ifs; - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s", + /* + * To allow backwards compatibility with higher level layers that + * assumed the REGDOM_CHANGE event is sent over the initially added + * interface. Find the highest parent of this interface and use it to + * send the event. + */ + 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 : ""); @@ -3022,14 +3236,16 @@ static void wpa_supplicant_update_channel_list( free_hw_features(ifs); ifs->hw.modes = wpa_drv_get_hw_feature_data( ifs, &ifs->hw.num_modes, &ifs->hw.flags); - } - /* Restart sched_scan with updated channel list */ - if (wpa_s->sched_scanning) { - wpa_dbg(wpa_s, MSG_DEBUG, - "Channel list changed restart sched scan."); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); + /* Restart PNO/sched_scan with updated channel list */ + if (ifs->pno) { + wpas_stop_pno(ifs); + wpas_start_pno(ifs); + } else if (ifs->sched_scanning && !ifs->pno_sched_pending) { + wpa_dbg(ifs, MSG_DEBUG, + "Channel list changed - restart sched_scan"); + wpas_scan_restart_sched_scan(ifs); + } } wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER); @@ -3120,6 +3336,14 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ if (category == WLAN_ACTION_RADIO_MEASUREMENT && + payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) { + wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa, + payload + 1, + plen - 1); + return; + } + + if (category == WLAN_ACTION_RADIO_MEASUREMENT && payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) { wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1); return; @@ -3209,6 +3433,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && event != EVENT_INTERFACE_STATUS && + event != EVENT_SCAN_RESULTS && event != EVENT_SCHED_SCAN_STOPPED) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore event %s (%d) while interface is disabled", @@ -3237,18 +3462,43 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, switch (event) { case EVENT_AUTH: +#ifdef CONFIG_FST + if (!wpas_fst_update_mbie(wpa_s, data->auth.ies, + data->auth.ies_len)) + wpa_printf(MSG_DEBUG, + "FST: MB IEs updated from auth IE"); +#endif /* CONFIG_FST */ sme_event_auth(wpa_s, data); break; case EVENT_ASSOC: +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_auth_resp) { + wpa_printf(MSG_INFO, + "EVENT_ASSOC - ignore_auth_resp active!"); + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpa_supplicant_event_assoc(wpa_s, data); if (data && data->assoc_info.authorized) wpa_supplicant_event_assoc_auth(wpa_s, data); + if (data) { + wpa_msg(wpa_s, MSG_INFO, + WPA_EVENT_SUBNET_STATUS_UPDATE "status=%u", + data->assoc_info.subnet_status); + } break; case EVENT_DISASSOC: wpas_event_disassoc(wpa_s, data ? &data->disassoc_info : NULL); break; case EVENT_DEAUTH: +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_auth_resp) { + wpa_printf(MSG_INFO, + "EVENT_DEAUTH - ignore_auth_resp active!"); + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpas_event_deauth(wpa_s, data ? &data->deauth_info : NULL); break; @@ -3257,10 +3507,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #ifndef CONFIG_NO_SCAN_PROCESSING case EVENT_SCAN_STARTED: - os_get_reltime(&wpa_s->scan_start_time); - if (wpa_s->own_scan_requested) { + if (wpa_s->own_scan_requested || + (data && !data->scan_info.external_scan)) { struct os_reltime diff; + os_get_reltime(&wpa_s->scan_start_time); os_reltime_sub(&wpa_s->scan_start_time, &wpa_s->scan_trigger_time, &diff); wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds", @@ -3283,7 +3534,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } break; case EVENT_SCAN_RESULTS: - if (os_reltime_initialized(&wpa_s->scan_start_time)) { + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + wpa_s->scan_res_handler = NULL; + wpa_s->own_scan_running = 0; + wpa_s->radio->external_scan_running = 0; + wpa_s->last_scan_req = NORMAL_SCAN_REQ; + break; + } + + if (!(data && data->scan_info.external_scan) && + os_reltime_initialized(&wpa_s->scan_start_time)) { struct os_reltime now, diff; os_get_reltime(&now); os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); @@ -3294,8 +3554,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } if (wpa_supplicant_event_scan_results(wpa_s, data)) break; /* interface may have been removed */ - wpa_s->own_scan_running = 0; - wpa_s->radio->external_scan_running = 0; + if (!(data && data->scan_info.external_scan)) + wpa_s->own_scan_running = 0; + if (data && data->scan_info.nl_scan_event) + wpa_s->radio->external_scan_running = 0; radio_work_check_next(wpa_s); break; #endif /* CONFIG_NO_SCAN_PROCESSING */ @@ -3336,13 +3598,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_ASSOC_REJECT: if (data->assoc_reject.bssid) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "bssid=" MACSTR " status_code=%u", + "bssid=" MACSTR " status_code=%u%s", MAC2STR(data->assoc_reject.bssid), - data->assoc_reject.status_code); + 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", - data->assoc_reject.status_code); + "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 { @@ -3398,17 +3664,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ #ifdef CONFIG_OFFCHANNEL wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst=" - MACSTR, MAC2STR(wpa_s->parent->pending_action_dst)); + MACSTR, MAC2STR(wpa_s->p2pdev->pending_action_dst)); /* * Catch TX status events for Action frames we sent via group - * interface in GO mode. + * interface in GO mode, or via standalone AP interface. + * Note, wpa_s->p2pdev will be the same as wpa_s->parent, + * except when the primary interface is used as a GO interface + * (for drivers which do not have group interface concurrency) */ if (data->tx_status.type == WLAN_FC_TYPE_MGMT && data->tx_status.stype == WLAN_FC_STYPE_ACTION && - os_memcmp(wpa_s->parent->pending_action_dst, + os_memcmp(wpa_s->p2pdev->pending_action_dst, data->tx_status.dst, ETH_ALEN) == 0) { offchannel_send_action_tx_status( - wpa_s->parent, data->tx_status.dst, + wpa_s->p2pdev, data->tx_status.dst, data->tx_status.data, data->tx_status.data_len, data->tx_status.ack ? @@ -3451,20 +3720,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.wds); break; case EVENT_CH_SWITCH: - if (!data) - break; - if (!wpa_s->ap_iface) { - wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch " - "event in non-AP mode"); + if (!data || !wpa_s->current_ssid) break; + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH + "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d", + data->ch_switch.freq, + data->ch_switch.ht_enabled, + data->ch_switch.ch_offset, + channel_width_to_string(data->ch_switch.ch_width), + data->ch_switch.cf1, + data->ch_switch.cf2); + + wpa_s->assoc_freq = data->ch_switch.freq; + wpa_s->current_ssid->frequency = data->ch_switch.freq; + + 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_P2P_GROUP_FORMATION) { + wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, + data->ch_switch.ht_enabled, + data->ch_switch.ch_offset, + data->ch_switch.ch_width, + data->ch_switch.cf1, + data->ch_switch.cf2); } - wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, - data->ch_switch.ht_enabled, - data->ch_switch.ch_offset, - data->ch_switch.ch_width, - data->ch_switch.cf1, - data->ch_switch.cf2); + wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS); break; #ifdef NEED_AP_MLME case EVENT_DFS_RADAR_DETECTED: @@ -3521,12 +3804,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ #ifdef CONFIG_P2P if (stype == WLAN_FC_STYPE_PROBE_REQ && - data->rx_mgmt.frame_len > 24) { + data->rx_mgmt.frame_len > IEEE80211_HDRLEN) { const u8 *src = mgmt->sa; - const u8 *ie = mgmt->u.probe_req.variable; - size_t ie_len = data->rx_mgmt.frame_len - - (mgmt->u.probe_req.variable - - data->rx_mgmt.frame); + const u8 *ie; + size_t ie_len; + + ie = data->rx_mgmt.frame + IEEE80211_HDRLEN; + ie_len = data->rx_mgmt.frame_len - + IEEE80211_HDRLEN; wpas_p2p_probe_req_rx( wpa_s, src, mgmt->da, mgmt->bssid, ie, ie_len, @@ -3566,11 +3851,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } if (stype == WLAN_FC_STYPE_PROBE_REQ && - data->rx_mgmt.frame_len > 24) { - const u8 *ie = mgmt->u.probe_req.variable; - size_t ie_len = data->rx_mgmt.frame_len - - (mgmt->u.probe_req.variable - - data->rx_mgmt.frame); + data->rx_mgmt.frame_len > IEEE80211_HDRLEN) { + const u8 *ie; + size_t ie_len; + + ie = data->rx_mgmt.frame + IEEE80211_HDRLEN; + ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN; wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da, mgmt->bssid, ie, ie_len, @@ -3713,6 +3999,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1); } wpa_supplicant_mark_disassoc(wpa_s); + wpa_bss_flush(wpa_s); radio_remove_works(wpa_s, NULL, 0); wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); @@ -3771,15 +4058,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->driver_gtk_rekey.replay_ctr); break; case EVENT_SCHED_SCAN_STOPPED: - wpa_s->pno = 0; wpa_s->sched_scanning = 0; - resched = wpa_s->scanning; + resched = wpa_s->scanning && wpas_scan_scheduled(wpa_s); wpa_supplicant_notify_scanning(wpa_s, 0); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) break; /* + * If the driver stopped scanning without being requested to, + * request a new scan to continue scanning for networks. + */ + if (!wpa_s->sched_scan_stop_req && + wpa_s->wpa_state == WPA_SCANNING) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Restart scanning after unexpected sched_scan stop event"); + wpa_supplicant_req_scan(wpa_s, 1, 0); + break; + } + + wpa_s->sched_scan_stop_req = 0; + + /* * Start a new sched scan to continue searching for more SSIDs * either if timed out or PNO schedule scan is pending. */ @@ -3820,8 +4120,72 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->mesh_peer.ie_len); #endif /* CONFIG_MESH */ break; + case EVENT_SURVEY: +#ifdef CONFIG_AP + if (!wpa_s->ap_iface) + break; + hostapd_event_get_survey(wpa_s->ap_iface, + &data->survey_results); +#endif /* CONFIG_AP */ + break; + case EVENT_ACS_CHANNEL_SELECTED: +#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 */ + break; + case EVENT_P2P_LO_STOP: +#ifdef CONFIG_P2P + wpa_s->p2p_lo_started = 0; + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP + P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d", + data->p2p_lo_stop.reason_code); +#endif /* CONFIG_P2P */ + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; } } + + +void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) +{ + struct wpa_supplicant *wpa_s; + + if (event != EVENT_INTERFACE_STATUS) + return; + + wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname); + if (wpa_s && wpa_s->driver->get_ifindex) { + unsigned int ifindex; + + ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv); + if (ifindex != data->interface_status.ifindex) { + wpa_dbg(wpa_s, MSG_DEBUG, + "interface status ifindex %d mismatch (%d)", + ifindex, data->interface_status.ifindex); + return; + } + } +#ifdef CONFIG_MATCH_IFACE + else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) { + struct wpa_interface *wpa_i; + + wpa_i = wpa_supplicant_match_iface( + ctx, data->interface_status.ifname); + if (!wpa_i) + return; + wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL); + os_free(wpa_i); + if (wpa_s) + wpa_s->matched = 1; + } +#endif /* CONFIG_MATCH_IFACE */ + + if (wpa_s) + wpa_supplicant_event(wpa_s, event, data); +} diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index 10ecce7..691de03 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -17,6 +17,7 @@ #include "common/wpa_ctrl.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" +#include "config.h" #include "driver_i.h" #include "offchannel.h" #include "gas_query.h" @@ -25,6 +26,9 @@ /** GAS query timeout in seconds */ #define GAS_QUERY_TIMEOUT_PERIOD 2 +/* GAS query wait-time / duration in ms */ +#define GAS_QUERY_WAIT_TIME_INITIAL 1000 +#define GAS_QUERY_WAIT_TIME_COMEBACK 150 /** * struct gas_query_pending - Pending GAS query @@ -37,6 +41,7 @@ struct gas_query_pending { u8 next_frag_id; unsigned int wait_comeback:1; unsigned int offchannel_tx_started:1; + unsigned int retry:1; int freq; u16 status_code; struct wpabuf *req; @@ -63,6 +68,10 @@ struct gas_query { static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); static void gas_query_timeout(void *eloop_data, void *user_ctx); +static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx); +static void gas_query_tx_initial_req(struct gas_query *gas, + struct gas_query_pending *query); +static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst); static int ms_from_time(struct os_reltime *last) @@ -108,8 +117,6 @@ 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_CANCELLED: - return "CANCELLED"; case GAS_QUERY_DELETED_AT_DEINIT: return "DELETED_AT_DEINIT"; } @@ -151,6 +158,7 @@ static void gas_query_done(struct gas_query *gas, offchannel_send_action_done(gas->wpa_s); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_cancel_timeout(gas_query_timeout, gas, query); + eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); dl_list_del(&query->list); query->cb(query->ctx, query->addr, query->dialog_token, result, query->adv_proto, query->resp, query->status_code); @@ -235,6 +243,13 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, eloop_cancel_timeout(gas_query_timeout, gas, query); 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); + eloop_register_timeout( + 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000, + gas_query_rx_comeback_timeout, gas, query); + } } if (result == OFFCHANNEL_SEND_ACTION_FAILED) { eloop_cancel_timeout(gas_query_timeout, gas, query); @@ -254,10 +269,13 @@ static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, - struct wpabuf *req) + struct wpabuf *req, unsigned int wait_time) { - unsigned int wait_time; int res, prot = pmf_in_use(gas->wpa_s, query->addr); + const u8 *bssid; + const u8 wildcard_bssid[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " "freq=%d prot=%d", MAC2STR(query->addr), @@ -267,12 +285,18 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, *categ = WLAN_ACTION_PROTECTED_DUAL; } os_get_reltime(&query->last_oper); - wait_time = 1000; 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)) + bssid = query->addr; + else + bssid = wildcard_bssid; res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, - gas->wpa_s->own_addr, query->addr, + gas->wpa_s->own_addr, bssid, wpabuf_head(req), wpabuf_len(req), wait_time, gas_query_tx_status, 0); if (res == 0) @@ -285,6 +309,7 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, struct gas_query_pending *query) { struct wpabuf *req; + unsigned int wait_time; req = gas_build_comeback_req(query->dialog_token); if (req == NULL) { @@ -292,7 +317,10 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, return; } - if (gas_query_tx(gas, query, req) < 0) { + wait_time = (query->retry || !query->offchannel_tx_started) ? + GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK; + + if (gas_query_tx(gas, query, req, wait_time) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); @@ -302,6 +330,35 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, } +static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx) +{ + struct gas_query *gas = eloop_data; + struct gas_query_pending *query = user_ctx; + int dialog_token; + + wpa_printf(MSG_DEBUG, + "GAS: No response to comeback request received (retry=%u)", + query->retry); + if (gas->current != query || query->retry) + return; + dialog_token = gas_query_new_dialog_token(gas, query->addr); + if (dialog_token < 0) + return; + wpa_printf(MSG_DEBUG, + "GAS: Retry GAS query due to comeback response timeout"); + query->retry = 1; + query->dialog_token = dialog_token; + *(wpabuf_mhead_u8(query->req) + 2) = dialog_token; + query->wait_comeback = 0; + query->next_frag_id = 0; + wpabuf_free(query->adv_proto); + query->adv_proto = NULL; + eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); + eloop_cancel_timeout(gas_query_timeout, gas, query); + gas_query_tx_initial_req(gas, query); +} + + static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) { struct gas_query *gas = eloop_data; @@ -319,6 +376,11 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas, { unsigned int secs, usecs; + if (comeback_delay > 1 && query->offchannel_tx_started) { + offchannel_send_action_done(gas->wpa_s); + query->offchannel_tx_started = 0; + } + secs = (comeback_delay * 1024) / 1000000; usecs = comeback_delay * 1024 - secs * 1000000; wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR @@ -371,6 +433,7 @@ static void gas_query_rx_comeback(struct gas_query *gas, "comeback_delay=%u)", MAC2STR(query->addr), query->dialog_token, frag_id, more_frags, comeback_delay); + eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || os_memcmp(adv_proto, wpabuf_head(query->adv_proto), @@ -447,8 +510,16 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, if (gas == NULL || len < 4) return -1; + pos = data; + action = *pos++; + dialog_token = *pos++; + + if (action != WLAN_PA_GAS_INITIAL_RESP && + action != WLAN_PA_GAS_COMEBACK_RESP) + return -1; /* Not a GAS response */ + prot = categ == WLAN_ACTION_PROTECTED_DUAL; - pmf = pmf_in_use(gas->wpa_s, bssid); + pmf = pmf_in_use(gas->wpa_s, sa); if (prot && !pmf) { wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled"); return 0; @@ -458,14 +529,6 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, return 0; } - pos = data; - action = *pos++; - dialog_token = *pos++; - - if (action != WLAN_PA_GAS_INITIAL_RESP && - action != WLAN_PA_GAS_COMEBACK_RESP) - return -1; /* Not a GAS response */ - query = gas_query_get_pending(gas, sa, dialog_token); if (query == NULL) { wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR @@ -620,11 +683,18 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) } gas->work = work; + gas_query_tx_initial_req(gas, query); +} - if (gas_query_tx(gas, query, query->req) < 0) { + +static void gas_query_tx_initial_req(struct gas_query *gas, + struct gas_query_pending *query) +{ + if (gas_query_tx(gas, query, query->req, + GAS_QUERY_WAIT_TIME_INITIAL) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); - gas_query_free(query, 1); + gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; } gas->current = query; @@ -633,7 +703,24 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) query->dialog_token); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); +} + + +static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) +{ + static int next_start = 0; + int dialog_token; + for (dialog_token = 0; dialog_token < 256; dialog_token++) { + if (gas_query_dialog_token_available( + gas, dst, (next_start + dialog_token) % 256)) + break; + } + if (dialog_token == 256) + return -1; /* Too many pending queries */ + dialog_token = (next_start + dialog_token) % 256; + next_start = (dialog_token + 1) % 256; + return dialog_token; } @@ -658,20 +745,13 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, { struct gas_query_pending *query; int dialog_token; - static int next_start = 0; if (wpabuf_len(req) < 3) return -1; - for (dialog_token = 0; dialog_token < 256; dialog_token++) { - if (gas_query_dialog_token_available( - gas, dst, (next_start + dialog_token) % 256)) - break; - } - if (dialog_token == 256) - return -1; /* Too many pending queries */ - dialog_token = (next_start + dialog_token) % 256; - next_start = (dialog_token + 1) % 256; + dialog_token = gas_query_new_dialog_token(gas, dst); + if (dialog_token < 0) + return -1; query = os_zalloc(sizeof(*query)); if (query == NULL) @@ -694,26 +774,10 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, query) < 0) { + query->req = NULL; /* caller will free this in error case */ gas_query_free(query, 1); return -1; } return dialog_token; } - - -/** - * gas_query_cancel - Cancel a pending GAS query - * @gas: GAS query data from gas_query_init() - * @dst: Destination MAC address for the query - * @dialog_token: Dialog token from gas_query_req() - */ -void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) -{ - struct gas_query_pending *query; - - query = gas_query_get_pending(gas, dst, dialog_token); - if (query) - gas_query_done(gas, query, GAS_QUERY_CANCELLED); - -} diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h index ad13490..ef82097 100644 --- a/wpa_supplicant/gas_query.h +++ b/wpa_supplicant/gas_query.h @@ -29,7 +29,6 @@ enum gas_query_result { GAS_QUERY_TIMEOUT, GAS_QUERY_PEER_ERROR, GAS_QUERY_INTERNAL_ERROR, - GAS_QUERY_CANCELLED, GAS_QUERY_DELETED_AT_DEINIT }; @@ -40,7 +39,6 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code), void *ctx); -void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token); #else /* CONFIG_GAS */ diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c index a1afc85..e88f147 100644 --- a/wpa_supplicant/hs20_supplicant.c +++ b/wpa_supplicant/hs20_supplicant.c @@ -25,6 +25,7 @@ #include "gas_query.h" #include "interworking.h" #include "hs20_supplicant.h" +#include "base64.h" #define OSU_MAX_ITEMS 10 @@ -60,6 +61,46 @@ struct osu_provider { }; +void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s) +{ + struct wpa_bss *bss = wpa_s->current_bss; + u8 *bssid = wpa_s->bssid; + const u8 *ie; + const u8 *ext_capa; + u32 filter = 0; + + if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) { + wpa_printf(MSG_DEBUG, + "Not configuring frame filtering - BSS " MACSTR + " is not a Hotspot 2.0 network", MAC2STR(bssid)); + return; + } + + ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE); + + /* Check if DGAF disabled bit is zero (5th byte in the IE) */ + if (!ie || ie[1] < 5) + wpa_printf(MSG_DEBUG, + "Not configuring frame filtering - Can't extract DGAF bit"); + else if (!(ie[6] & HS20_DGAF_DISABLED)) + filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK; + + ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); + if (!ext_capa || ext_capa[1] < 2) { + wpa_printf(MSG_DEBUG, + "Not configuring frame filtering - Can't extract Proxy ARP bit"); + return; + } + + /* Check if Proxy ARP is enabled (2nd byte in the IE) */ + if (ext_capa[3] & BIT(4)) + filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP | + WPA_DATA_FRAME_FILTER_FLAG_NA; + + wpa_drv_configure_frame_filters(wpa_s, filter); +} + + void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id) { u8 conf; @@ -164,8 +205,8 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, } -struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, - size_t payload_len) +static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, + size_t payload_len) { struct wpabuf *buf; @@ -180,13 +221,14 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, - const u8 *payload, size_t payload_len) + const u8 *payload, size_t payload_len, int inmem) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; + struct icon_entry *icon_entry; bss = wpa_bss_get_bssid(wpa_s, dst); if (!bss) { @@ -210,15 +252,127 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); - ret = -1; + return -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); + if (inmem) { + icon_entry = os_zalloc(sizeof(struct icon_entry)); + if (!icon_entry) + return -1; + os_memcpy(icon_entry->bssid, dst, ETH_ALEN); + icon_entry->file_name = os_malloc(payload_len + 1); + if (!icon_entry->file_name) { + os_free(icon_entry); + return -1; + } + os_memcpy(icon_entry->file_name, payload, payload_len); + icon_entry->file_name[payload_len] = '\0'; + icon_entry->dialog_token = res; + + dl_list_add(&wpa_s->icon_head, &icon_entry->list); + } + return ret; } +static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s, + const u8 *bssid, + const char *file_name) +{ + struct icon_entry *icon; + + dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { + if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 && + os_strcmp(icon->file_name, file_name) == 0 && icon->image) + return icon; + } + + return NULL; +} + + +int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name, size_t offset, size_t size, + char *reply, size_t buf_len) +{ + struct icon_entry *icon; + size_t out_size; + unsigned char *b64; + size_t b64_size; + int reply_size; + + wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)", + MAC2STR(bssid), file_name, (unsigned int) offset, + (unsigned int) size, (unsigned int) buf_len); + + icon = hs20_find_icon(wpa_s, bssid, file_name); + if (!icon || !icon->image || offset >= icon->image_len) + return -1; + if (size > icon->image_len - offset) + size = icon->image_len - offset; + out_size = buf_len - 3 /* max base64 padding */; + if (size * 4 > out_size * 3) + size = out_size * 3 / 4; + if (size == 0) + return -1; + + b64 = base64_encode(&icon->image[offset], size, &b64_size); + if (b64 && buf_len >= b64_size) { + os_memcpy(reply, b64, b64_size); + reply_size = b64_size; + } else { + reply_size = -1; + } + os_free(b64); + return reply_size; +} + + +static void hs20_free_icon_entry(struct icon_entry *icon) +{ + wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR + " dialog_token=%u file_name=%s image_len=%u", + MAC2STR(icon->bssid), icon->dialog_token, + icon->file_name ? icon->file_name : "N/A", + (unsigned int) icon->image_len); + os_free(icon->file_name); + os_free(icon->image); + os_free(icon); +} + + +int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name) +{ + struct icon_entry *icon, *tmp; + int count = 0; + + if (!bssid) + wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons"); + else if (!file_name) + wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for " + MACSTR, MAC2STR(bssid)); + else + wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for " + MACSTR " file name %s", MAC2STR(bssid), file_name); + + dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, + list) { + if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) && + (!file_name || + os_strcmp(icon->file_name, file_name) == 0)) { + dl_list_del(&icon->list); + hs20_free_icon_entry(icon); + count++; + } + } + return count == 0 ? -1 : 0; +} + + static void hs20_set_osu_access_permission(const char *osu_dir, const char *fname) { @@ -243,16 +397,53 @@ static void hs20_set_osu_access_permission(const char *osu_dir, } } + +static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s, + struct icon_entry *new_icon) +{ + struct icon_entry *icon, *tmp; + + dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, + list) { + if (icon == new_icon) + continue; + if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 && + os_strcmp(icon->file_name, new_icon->file_name) == 0) { + dl_list_del(&icon->list); + hs20_free_icon_entry(icon); + } + } +} + + static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *pos, - size_t slen) + size_t slen, u8 dialog_token) { char fname[256]; int png; FILE *f; u16 data_len; + struct icon_entry *icon; + + 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); + 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, + RX_HS20_ICON MACSTR " %s %u", + MAC2STR(sa), icon->file_name, + (unsigned int) icon->image_len); + return 0; + } + } - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File", + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File", MAC2STR(sa)); if (slen < 4) { @@ -315,7 +506,7 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, } fclose(f); - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname); return 0; } @@ -358,7 +549,7 @@ static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res) 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) + const u8 *data, size_t slen, u8 dialog_token) { const u8 *pos = data; u8 subtype; @@ -379,7 +570,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " HS Capability List", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); if (anqp) { @@ -389,7 +580,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Operator Friendly Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); if (anqp) { @@ -405,7 +596,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, "Metrics value from " MACSTR, MAC2STR(sa)); break; } - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa), pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5), pos[9], pos[10], WPA_GET_LE16(pos + 11)); @@ -415,7 +606,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_CONNECTION_CAPABILITY: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Connection Capability", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); if (anqp) { @@ -425,7 +616,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATING_CLASS: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Operating Class", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); if (anqp) { @@ -435,7 +626,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OSU_PROVIDERS_LIST: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " OSU Providers list", MAC2STR(sa)); wpa_s->num_prov_found++; if (anqp) { @@ -445,7 +636,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_ICON_BINARY_FILE: - ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen); + ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen, + dialog_token); if (wpa_s->fetch_osu_icon_in_progress) { hs20_osu_icon_fetch_result(wpa_s, ret); eloop_cancel_timeout(hs20_continue_icon_fetch, @@ -511,7 +703,10 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s) wpa_s->conf->osu_dir); f = fopen(fname, "w"); if (f == NULL) { + wpa_msg(wpa_s, MSG_INFO, + "Could not write OSU provider information"); hs20_free_osu_prov(wpa_s); + wpa_s->fetch_anqp_in_progress = 0; return; } @@ -579,7 +774,8 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s) if (hs20_anqp_send_req(wpa_s, osu->bssid, BIT(HS20_STYPE_ICON_REQUEST), (u8 *) icon->filename, - os_strlen(icon->filename)) < 0) { + os_strlen(icon->filename), + 0) < 0) { icon->failed = 1; continue; } @@ -617,7 +813,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, prov->osu_ssid_len = osu_ssid_len; /* OSU Friendly Name Length */ - if (pos + 2 > end) { + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Friendly Name Length"); return; @@ -633,9 +829,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += len2; /* OSU Friendly Name Duples */ - while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) { + while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) { struct osu_lang_string *f; - if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) { + if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) { wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name"); break; } @@ -646,7 +842,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } /* OSU Server URI */ - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server URI length"); return; @@ -661,7 +857,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += uri_len; /* OSU Method list */ - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method " "list length"); return; @@ -681,7 +877,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } /* Icons Available Length */ - if (pos + 2 > end) { + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons " "Available Length"); return; @@ -701,7 +897,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct osu_icon *icon = &prov->icon[prov->icon_count]; u8 flen; - if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) { + if (2 + 2 + 3 + 1 + 1 > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata"); break; } @@ -713,46 +909,46 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, os_memcpy(icon->lang, pos2, 3); pos2 += 3; - flen = pos2[0]; - if (flen > pos - pos2 - 1) { + flen = *pos2++; + if (flen > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type"); break; } - os_memcpy(icon->icon_type, pos2 + 1, flen); - pos2 += 1 + flen; + os_memcpy(icon->icon_type, pos2, flen); + pos2 += flen; - if (pos2 + 1 > pos) { + if (pos - pos2 < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " "Filename length"); break; } - flen = pos2[0]; - if (flen > pos - pos2 - 1) { + flen = *pos2++; + if (flen > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " "Filename"); break; } - os_memcpy(icon->filename, pos2 + 1, flen); - pos2 += 1 + flen; + os_memcpy(icon->filename, pos2, flen); + pos2 += flen; prov->icon_count++; } /* OSU_NAI */ - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); return; } - osu_nai_len = pos[0]; - if (osu_nai_len > end - pos - 1) { + osu_nai_len = *pos++; + if (osu_nai_len > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); return; } - os_memcpy(prov->osu_nai, pos + 1, osu_nai_len); - pos += 1 + osu_nai_len; + os_memcpy(prov->osu_nai, pos, osu_nai_len); + pos += osu_nai_len; /* OSU Service Description Length */ - if (pos + 2 > end) { + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Service Description Length"); return; @@ -768,20 +964,20 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += len2; /* OSU Service Description Duples */ - while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) { + while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) { struct osu_lang_string *f; u8 descr_len; - descr_len = pos2[0]; - if (descr_len > pos - pos2 - 1 || descr_len < 3) { + descr_len = *pos2++; + if (descr_len > pos - pos2 || descr_len < 3) { wpa_printf(MSG_DEBUG, "Invalid OSU Service " "Description"); break; } f = &prov->serv_desc[prov->serv_desc_count++]; - os_memcpy(f->lang, pos2 + 1, 3); - os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3); - pos2 += 1 + descr_len; + os_memcpy(f->lang, pos2, 3); + os_memcpy(f->text, pos2 + 3, descr_len - 3); + pos2 += descr_len; } wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR, @@ -816,9 +1012,9 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) end = pos + wpabuf_len(prov_anqp); /* OSU SSID */ - if (pos + 1 > end) + if (end - pos < 1) continue; - if (pos + 1 + pos[0] > end) { + if (1 + pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " "OSU SSID"); continue; @@ -832,7 +1028,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) osu_ssid = pos; pos += osu_ssid_len; - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " "Number of OSU Providers"); continue; @@ -842,7 +1038,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) num_providers); /* OSU Providers */ - while (pos + 2 < end && num_providers > 0) { + while (end - pos > 2 && num_providers > 0) { num_providers--; len = WPA_GET_LE16(pos); pos += 2; @@ -882,7 +1078,7 @@ static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s, } -int hs20_fetch_osu(struct wpa_supplicant *wpa_s) +int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan) { if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - " @@ -913,7 +1109,16 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch"); wpa_s->num_osu_scans = 0; wpa_s->num_prov_found = 0; - hs20_start_osu_scan(wpa_s); + if (skip_scan) { + wpa_s->network_select = 0; + wpa_s->fetch_all_anqp = 1; + wpa_s->fetch_osu_info = 1; + wpa_s->fetch_osu_icon_in_progress = 0; + + interworking_start_fetch_anqp(wpa_s); + } else { + hs20_start_osu_scan(wpa_s); + } return 0; } @@ -1002,8 +1207,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, } +void hs20_init(struct wpa_supplicant *wpa_s) +{ + dl_list_init(&wpa_s->icon_head); +} + + void hs20_deinit(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); hs20_free_osu_prov(wpa_s); + if (wpa_s->icon_head.next) + hs20_del_icon(wpa_s, NULL, NULL); } diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h index 85b5120..0dd559f 100644 --- a/wpa_supplicant/hs20_supplicant.h +++ b/wpa_supplicant/hs20_supplicant.h @@ -8,17 +8,16 @@ #ifndef HS20_SUPPLICANT_H #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); int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, - const u8 *payload, size_t payload_len); -struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, - size_t payload_len); + const u8 *payload, size_t payload_len, int inmem); void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, struct wpabuf *buf); 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); + const u8 *data, size_t slen, u8 dialog_token); 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); @@ -32,10 +31,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, void hs20_free_osu_prov(struct wpa_supplicant *wpa_s); void hs20_next_osu_icon(struct wpa_supplicant *wpa_s); void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s); -int hs20_fetch_osu(struct wpa_supplicant *wpa_s); +int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan); void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s); void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s); void hs20_start_osu_scan(struct wpa_supplicant *wpa_s); +void hs20_init(struct wpa_supplicant *wpa_s); void hs20_deinit(struct wpa_supplicant *wpa_s); +int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name, size_t offset, size_t size, + char *reply, size_t buf_len); +int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name); #endif /* HS20_SUPPLICANT_H */ diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index d9d0ae7..53d7d57 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -221,6 +221,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, peer->supp = wpa_sm_init(ctx); if (peer->supp == NULL) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); + os_free(ctx); return -1; } @@ -230,7 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); - wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL); peer->supp_ie_len = sizeof(peer->supp_ie); if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, @@ -404,7 +405,7 @@ static void auth_set_eapol(void *ctx, const u8 *addr, static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, - const u8 *own_addr) + const u8 *own_addr, struct wpa_ssid *ssid) { struct wpa_auth_config conf; struct wpa_auth_callbacks cb; @@ -418,7 +419,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, conf.rsn_pairwise = WPA_CIPHER_CCMP; conf.wpa_group = WPA_CIPHER_CCMP; conf.eapol_version = 2; - conf.wpa_group_rekey = 600; + conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600; os_memset(&cb, 0, sizeof(cb)); cb.ctx = ibss_rsn; @@ -665,7 +666,8 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) } -struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) +struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) { struct ibss_rsn *ibss_rsn; @@ -674,7 +676,7 @@ struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) return NULL; ibss_rsn->wpa_s = wpa_s; - if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { + if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) { ibss_rsn_deinit(ibss_rsn); return NULL; } diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h index 67fae2d..626c543 100644 --- a/wpa_supplicant/ibss_rsn.h +++ b/wpa_supplicant/ibss_rsn.h @@ -51,7 +51,8 @@ struct ibss_rsn { }; -struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s); +struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn); int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr); void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac); diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index fd47c17..1fb40c7 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -362,13 +362,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, u8 elen, auth_count, a; const u8 *e_end; - if (pos + 3 > end) { + if (end - pos < 3) { wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); return NULL; } elen = *pos++; - if (pos + elen > end || elen < 2) { + if (elen > end - pos || elen < 2) { wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); return NULL; } @@ -381,14 +381,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, for (a = 0; a < auth_count; a++) { u8 id, len; - if (pos + 2 > end || pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "No room for Authentication " - "Parameter subfield"); + if (end - pos < 2) { + wpa_printf(MSG_DEBUG, + "No room for Authentication Parameter subfield header"); return NULL; } id = *pos++; len = *pos++; + if (len > end - pos) { + wpa_printf(MSG_DEBUG, + "No room for Authentication Parameter subfield"); + return NULL; + } switch (id) { case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: @@ -463,7 +468,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ pos += 2; - if (pos + len > end || len < 3) { + if (len > end - pos || len < 3) { wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " "(len=%u; left=%u)", len, (unsigned int) (end - pos)); @@ -473,7 +478,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, r->encoding = *pos++; realm_len = *pos++; - if (pos + realm_len > f_end) { + if (realm_len > f_end - pos) { wpa_printf(MSG_DEBUG, "No room for NAI Realm " "(len=%u; left=%u)", realm_len, (unsigned int) (f_end - pos)); @@ -485,13 +490,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, return NULL; pos += realm_len; - if (pos + 1 > f_end) { + if (f_end - pos < 1) { wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); return NULL; } r->eap_count = *pos++; wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); - if (pos + r->eap_count * 3 > f_end) { + if (r->eap_count * 3 > f_end - pos) { wpa_printf(MSG_DEBUG, "No room for EAP Methods"); return NULL; } @@ -746,7 +751,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) return 0; pos = wpabuf_head_u8(anqp); end = pos + wpabuf_len(anqp); - if (pos + 2 > end) + if (end - pos < 2) return 0; if (*pos != 0) { wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); @@ -754,7 +759,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) } pos++; udhl = *pos++; - if (pos + udhl > end) { + if (udhl > end - pos) { wpa_printf(MSG_DEBUG, "Invalid UDHL"); return 0; } @@ -764,12 +769,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2], imsi, mnc_len); - while (pos + 2 <= end) { + while (end - pos >= 2) { u8 iei, len; const u8 *l_end; iei = *pos++; len = *pos++ & 0x7f; - if (pos + len > end) + if (len > end - pos) break; l_end = pos + len; @@ -780,7 +785,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) pos, len); num = *pos++; for (i = 0; i < num; i++) { - if (pos + 3 > l_end) + if (l_end - pos < 3) break; if (os_memcmp(pos, plmn, 3) == 0 || os_memcmp(pos, plmn2, 3) == 0) @@ -945,11 +950,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, if (!key_mgmt) key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ? "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP"; - if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0) - return -1; - if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) - return -1; - if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) + if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 || + wpa_config_set(ssid, "proto", "RSN", 0) < 0 || + wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) return -1; return 0; } @@ -1082,12 +1085,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, * OI #1, [OI #2], [OI #3] */ - if (pos + 2 > end) + if (end - pos < 2) return 0; pos++; /* skip Number of ANQP OIs */ lens = *pos++; - if (pos + (lens & 0x0f) + (lens >> 4) > end) + if ((lens & 0x0f) + (lens >> 4) > end - pos) return 0; if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) @@ -1121,7 +1124,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, /* Set of <OI Length, OI> duples */ while (pos < end) { len = *pos++; - if (pos + len > end) + if (len > end - pos) break; if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; @@ -1182,6 +1185,7 @@ static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss) static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { +#ifdef CONFIG_HS20 int res; unsigned int dl_bandwidth, ul_bandwidth; const u8 *wan; @@ -1233,6 +1237,7 @@ static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, if (cred->min_ul_bandwidth_roaming > ul_bandwidth) return 1; } +#endif /* CONFIG_HS20 */ return 0; } @@ -1260,9 +1265,11 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_HS20 + static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) { - while (pos + 4 <= end) { + while (end - pos >= 4) { if (pos[0] == proto && pos[3] == 1 /* Open */) return 1; pos += 4; @@ -1275,7 +1282,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, u16 port) { - while (pos + 4 <= end) { + while (end - pos >= 4) { if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port && pos[3] == 1 /* Open */) return 1; @@ -1285,10 +1292,13 @@ static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, return 0; } +#endif /* CONFIG_HS20 */ + static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { +#ifdef CONFIG_HS20 int res; const u8 *capab, *end; unsigned int i, j; @@ -1325,6 +1335,7 @@ static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, } } } +#endif /* CONFIG_HS20 */ return 0; } @@ -1438,7 +1449,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, os_free(anon); } - if (cred->username && cred->username[0] && + if (!ttls && cred->username && cred->username[0] && cred->realm && + !os_strchr(cred->username, '@')) { + char *id; + size_t buflen; + int res; + + buflen = os_strlen(cred->username) + 1 + + os_strlen(cred->realm) + 1; + + id = os_malloc(buflen); + if (!id) + return -1; + os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm); + res = wpa_config_set_quoted(ssid, "identity", id); + os_free(id); + if (res < 0) + return -1; + } else if (cred->username && cred->username[0] && wpa_config_set_quoted(ssid, "identity", cred->username) < 0) return -1; @@ -1560,9 +1588,8 @@ fail: } -static int interworking_connect_helper(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, int allow_excluded, - int only_add) +int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + int only_add) { struct wpa_cred *cred, *cred_rc, *cred_3gpp; struct wpa_ssid *ssid; @@ -1570,7 +1597,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, struct nai_realm_eap *eap = NULL; u16 count, i; char buf[100]; - int excluded = 0, *excl = allow_excluded ? &excluded : NULL; + int excluded = 0, *excl = &excluded; const char *name; if (wpa_s->conf->cred == NULL || bss == NULL) @@ -1584,8 +1611,8 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, } wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR - " for connection (allow_excluded=%d)", - MAC2STR(bss->bssid), allow_excluded); + " for connection", + MAC2STR(bss->bssid)); if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { /* @@ -1603,7 +1630,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d", cred_rc->priority, cred_rc->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1612,7 +1639,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d", cred->priority, cred->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1622,7 +1649,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest 3GPP matching credential priority %d sp_priority %d", cred_3gpp->priority, cred_3gpp->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1635,7 +1662,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)", cred_rc->priority, cred_rc->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1645,7 +1672,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)", cred->priority, cred->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1655,7 +1682,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)", cred_3gpp->priority, cred_3gpp->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } } @@ -1820,13 +1847,6 @@ fail: } -int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - int only_add) -{ - return interworking_connect_helper(wpa_s, bss, 1, only_add); -} - - #ifdef PCSC_FUNCS static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s) { @@ -2125,23 +2145,27 @@ int domain_name_list_contains(struct wpabuf *domain_names, pos = wpabuf_head(domain_names); end = pos + wpabuf_len(domain_names); - while (pos + 1 < end) { - if (pos + 1 + pos[0] > end) + while (end - pos > 1) { + u8 elen; + + elen = *pos++; + if (elen > end - pos) break; wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", - pos + 1, pos[0]); - if (pos[0] == len && - os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) + pos, elen); + if (elen == len && + os_strncasecmp(domain, (const char *) pos, len) == 0) return 1; - if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') { - const char *ap = (const char *) (pos + 1); - int offset = pos[0] - len; + if (!exact_match && elen > len && pos[elen - len - 1] == '.') { + const char *ap = (const char *) pos; + int offset = elen - len; + if (os_strncasecmp(domain, ap + offset, len) == 0) return 1; } - pos += 1 + pos[0]; + pos += elen; } return 0; @@ -2564,11 +2588,13 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) return; } +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) { wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)"); hs20_next_osu_icon(wpa_s); return; } +#endif /* CONFIG_HS20 */ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!(bss->caps & IEEE80211_CAP_ESS)) @@ -2602,6 +2628,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) } if (found == 0) { +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_info) { if (wpa_s->num_prov_found == 0 && wpa_s->fetch_osu_waiting_scan && @@ -2614,6 +2641,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) hs20_osu_icon_fetch(wpa_s); return; } +#endif /* CONFIG_HS20 */ wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); wpa_s->fetch_anqp_in_progress = 0; if (wpa_s->network_select) @@ -2664,10 +2692,11 @@ 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) + u16 info_ids[], size_t num_ids, u32 subtypes, + int get_cell_pref) { struct wpabuf *buf; - struct wpabuf *hs20_buf = NULL; + struct wpabuf *extra_buf = NULL; int ret = 0; int freq; struct wpa_bss *bss; @@ -2690,15 +2719,31 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, #ifdef CONFIG_HS20 if (subtypes != 0) { - hs20_buf = wpabuf_alloc(100); - if (hs20_buf == NULL) + extra_buf = wpabuf_alloc(100); + if (extra_buf == NULL) return -1; - hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf); + hs20_put_anqp_req(subtypes, NULL, 0, extra_buf); } #endif /* CONFIG_HS20 */ - buf = anqp_build_req(info_ids, num_ids, hs20_buf); - wpabuf_free(hs20_buf); +#ifdef CONFIG_MBO + if (get_cell_pref) { + struct wpabuf *mbo; + + mbo = mbo_build_anqp_buf(wpa_s, bss); + if (mbo) { + if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) { + wpabuf_free(extra_buf); + return -1; + } + wpabuf_put_buf(extra_buf, mbo); + wpabuf_free(mbo); + } + } +#endif /* CONFIG_MBO */ + + buf = anqp_build_req(info_ids, num_ids, extra_buf); + wpabuf_free(extra_buf); if (buf == NULL) return -1; @@ -2716,10 +2761,46 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, } +static void anqp_add_extra(struct wpa_supplicant *wpa_s, + struct wpa_bss_anqp *anqp, u16 info_id, + const u8 *data, size_t slen) +{ + struct wpa_bss_anqp_elem *tmp, *elem = NULL; + + if (!anqp) + return; + + dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem, + list) { + if (tmp->infoid == info_id) { + elem = tmp; + break; + } + } + + if (!elem) { + elem = os_zalloc(sizeof(*elem)); + if (!elem) + return; + elem->infoid = info_id; + dl_list_add(&anqp->anqp_elems, &elem->list); + } else { + wpabuf_free(elem->payload); + } + + elem->payload = wpabuf_alloc_copy(data, slen); + if (!elem->payload) { + dl_list_del(&elem->list); + os_free(elem); + } +} + + static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, - const u8 *data, size_t slen) + const u8 *data, size_t slen, + u8 dialog_token) { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; @@ -2732,7 +2813,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, switch (info_id) { case ANQP_CAPABILITY_LIST: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " ANQP Capability list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list", pos, slen); @@ -2742,7 +2823,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_VENUE_NAME: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); if (anqp) { @@ -2751,7 +2832,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_NETWORK_AUTH_TYPE: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Network Authentication Type information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " @@ -2762,7 +2843,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_ROAMING_CONSORTIUM: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Roaming Consortium list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", pos, slen); @@ -2772,7 +2853,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " IP Address Type Availability information", MAC2STR(sa)); wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", @@ -2784,7 +2865,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_NAI_REALM: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " NAI Realm list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); if (anqp) { @@ -2793,7 +2874,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_3GPP_CELLULAR_NETWORK: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " 3GPP Cellular Network information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", pos, slen); @@ -2803,7 +2884,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_DOMAIN_NAME: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Domain Name list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); if (anqp) { @@ -2829,7 +2910,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, switch (type) { case HS20_ANQP_OUI_TYPE: hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa, - pos, slen); + pos, slen, + dialog_token); break; default: wpa_msg(wpa_s, MSG_DEBUG, @@ -2849,6 +2931,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, default: wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Unsupported ANQP Info ID %u", info_id); + anqp_add_extra(wpa_s, anqp, info_id, data, slen); break; } } @@ -2871,8 +2954,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, " dialog_token=%u result=%d status_code=%u", MAC2STR(dst), dialog_token, result, status_code); if (result != GAS_QUERY_SUCCESS) { +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); +#endif /* CONFIG_HS20 */ anqp_result = "FAILURE"; goto out; } @@ -2882,8 +2967,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Unexpected Advertisement Protocol in response"); +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); +#endif /* CONFIG_HS20 */ anqp_result = "INVALID_FRAME"; goto out; } @@ -2927,12 +3014,14 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, goto out_parse_done; } interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos, - slen); + slen, dialog_token); pos += slen; } out_parse_done: +#ifdef CONFIG_HS20 hs20_notify_parse_done(wpa_s); +#endif /* CONFIG_HS20 */ out: wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s", MAC2STR(dst), anqp_result); diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 3743dc0..3d22292 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -12,7 +12,8 @@ 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); + u16 info_ids[], size_t num_ids, u32 subtypes, + int get_cell_pref); 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/wpa_supplicant/libwpa_test.c b/wpa_supplicant/libwpa_test.c new file mode 100644 index 0000000..e51ab72 --- /dev/null +++ b/wpa_supplicant/libwpa_test.c @@ -0,0 +1,32 @@ +/* + * libwpa_test - Test program for libwpa_client.* library linking + * Copyright (c) 2015, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common/wpa_ctrl.h" + +int main(int argc, char *argv[]) +{ + struct wpa_ctrl *ctrl; + + ctrl = wpa_ctrl_open("foo"); + if (!ctrl) + return -1; + if (wpa_ctrl_attach(ctrl) == 0) + wpa_ctrl_detach(ctrl); + if (wpa_ctrl_pending(ctrl)) { + char buf[10]; + size_t len; + + len = sizeof(buf); + wpa_ctrl_recv(ctrl, buf, &len); + } + wpa_ctrl_close(ctrl); + + return 0; +} diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c index d5d47e1..e08c2fd 100644 --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -65,41 +65,44 @@ static void usage(void) " -B = run daemon in the background\n" " -c = Configuration file\n" " -C = ctrl_interface parameter (only used if -c is not)\n" - " -i = interface name\n" - " -I = additional configuration file\n" " -d = increase debugging verbosity (-dd even more)\n" " -D = driver name (can be multiple drivers: nl80211,wext)\n" - " -e = entropy file\n"); + " -e = entropy file\n" #ifdef CONFIG_DEBUG_FILE - printf(" -f = log output to debug file instead of stdout\n"); + " -f = log output to debug file instead of stdout\n" #endif /* CONFIG_DEBUG_FILE */ - printf(" -g = global ctrl_interface\n" + " -g = global ctrl_interface\n" " -G = global ctrl_interface group\n" - " -K = include keys (passwords, etc.) in debug output\n"); -#ifdef CONFIG_DEBUG_SYSLOG - printf(" -s = log output to syslog instead of stdout\n"); -#endif /* CONFIG_DEBUG_SYSLOG */ -#ifdef CONFIG_DEBUG_LINUX_TRACING - printf(" -T = record to Linux tracing in addition to logging\n"); - printf(" (records all messages regardless of debug verbosity)\n"); -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - printf(" -t = include timestamp in debug messages\n" " -h = show this help text\n" + " -i = interface name\n" + " -I = additional configuration file\n" + " -K = include keys (passwords, etc.) in debug output\n" " -L = show license (BSD)\n" +#ifdef CONFIG_P2P + " -m = Configuration file for the P2P Device interface\n" +#endif /* CONFIG_P2P */ +#ifdef CONFIG_MATCH_IFACE + " -M = start describing new matching interface\n" +#endif /* CONFIG_MATCH_IFACE */ + " -N = start describing new interface\n" " -o = override driver parameter for new interfaces\n" " -O = override ctrl_interface parameter for new interfaces\n" " -p = driver parameters\n" " -P = PID file\n" - " -q = decrease debugging verbosity (-qq even less)\n"); + " -q = decrease debugging verbosity (-qq even less)\n" +#ifdef CONFIG_DEBUG_SYSLOG + " -s = log output to syslog instead of stdout\n" +#endif /* CONFIG_DEBUG_SYSLOG */ + " -t = include timestamp in debug messages\n" +#ifdef CONFIG_DEBUG_LINUX_TRACING + " -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 - printf(" -u = enable DBus control interface\n"); + " -u = enable DBus control interface\n" #endif /* CONFIG_DBUS */ - printf(" -v = show version\n" - " -W = wait for a control interface monitor before starting\n" -#ifdef CONFIG_P2P - " -m = Configuration file for the P2P Device interface\n" -#endif /* CONFIG_P2P */ - " -N = start describing new interface\n"); + " -v = show version\n" + " -W = wait for a control interface monitor before starting\n"); printf("example:\n" " wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n", @@ -153,6 +156,28 @@ static void wpa_supplicant_fd_workaround(int start) } +#ifdef CONFIG_MATCH_IFACE +static int wpa_supplicant_init_match(struct wpa_global *global) +{ + /* + * The assumption is that the first driver is the primary driver and + * will handle the arrival / departure of interfaces. + */ + if (wpa_drivers[0]->global_init && !global->drv_priv[0]) { + global->drv_priv[0] = wpa_drivers[0]->global_init(global); + if (!global->drv_priv[0]) { + wpa_printf(MSG_ERROR, + "Failed to initialize driver '%s'", + wpa_drivers[0]->name); + return -1; + } + } + + return 0; +} +#endif /* CONFIG_MATCH_IFACE */ + + int main(int argc, char *argv[]) { int c, i; @@ -176,7 +201,7 @@ int main(int argc, char *argv[]) for (;;) { c = getopt(argc, argv, - "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW"); + "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW"); if (c < 0) break; switch (c) { @@ -282,6 +307,20 @@ int main(int argc, char *argv[]) case 'W': params.wait_for_monitor++; break; +#ifdef CONFIG_MATCH_IFACE + case 'M': + params.match_iface_count++; + iface = os_realloc_array(params.match_ifaces, + params.match_iface_count, + sizeof(struct wpa_interface)); + if (!iface) + goto out; + params.match_ifaces = iface; + iface = ¶ms.match_ifaces[params.match_iface_count - + 1]; + os_memset(iface, 0, sizeof(*iface)); + break; +#endif /* CONFIG_MATCH_IFACE */ case 'N': iface_count++; iface = os_realloc_array(ifaces, iface_count, @@ -328,6 +367,9 @@ int main(int argc, char *argv[]) ifaces[i].ctrl_interface == NULL) || ifaces[i].ifname == NULL) { if (iface_count == 1 && (params.ctrl_interface || +#ifdef CONFIG_MATCH_IFACE + params.match_iface_count || +#endif /* CONFIG_MATCH_IFACE */ params.dbus_ctrl_interface)) break; usage(); @@ -341,6 +383,11 @@ int main(int argc, char *argv[]) } } +#ifdef CONFIG_MATCH_IFACE + if (exitcode == 0) + exitcode = wpa_supplicant_init_match(global); +#endif /* CONFIG_MATCH_IFACE */ + if (exitcode == 0) exitcode = wpa_supplicant_run(global); @@ -351,6 +398,9 @@ int main(int argc, char *argv[]) out: wpa_supplicant_fd_workaround(0); os_free(ifaces); +#ifdef CONFIG_MATCH_IFACE + os_free(params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ os_free(params.pid_file); os_program_deinit(); diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c new file mode 100644 index 0000000..7e049be --- /dev/null +++ b/wpa_supplicant/mbo.c @@ -0,0 +1,836 @@ +/* + * wpa_supplicant - MBO + * + * 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_defs.h" +#include "common/gas.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" +#include "bss.h" +#include "scan.h" + +/* type + length + oui + oui type */ +#define MBO_IE_HEADER 6 + + +static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason) +{ + if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE) + return -1; + + /* Only checking the validity of the channel and oper_class */ + if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1) + return -1; + + return 0; +} + + +const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) +{ + const u8 *mbo, *end; + + if (!bss) + return NULL; + + mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); + if (!mbo) + return NULL; + + end = mbo + 2 + mbo[1]; + mbo += MBO_IE_HEADER; + + return get_ie(mbo, end - mbo, attr); +} + + +static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, + u8 start, u8 end) +{ + u8 i; + + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class); + + for (i = start; i < end; i++) + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan); + + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference); + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason); +} + + +static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, u8 start, u8 end) +{ + size_t size = end - start + 3; + + 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_body(wpa_s, mbo, start, end); +} + + +static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len) +{ + wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(mbo, len); /* Length */ + wpabuf_put_be24(mbo, OUI_WFA); + wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT); +} + + +static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, u8 start, + u8 end) +{ + size_t size = end - start + 7; + + if (size + 2 > wpabuf_tailroom(mbo)) + return; + + wpas_mbo_non_pref_chan_subelem_hdr(mbo, size); + wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end); +} + + +static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, int subelement) +{ + u8 i, start = 0; + struct wpa_mbo_non_pref_channel *start_pref; + + if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) { + if (subelement) + wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4); + return; + } + start_pref = &wpa_s->non_pref_chan[0]; + + for (i = 1; i <= wpa_s->non_pref_chan_num; i++) { + struct wpa_mbo_non_pref_channel *non_pref = NULL; + + if (i < wpa_s->non_pref_chan_num) + non_pref = &wpa_s->non_pref_chan[i]; + if (!non_pref || + non_pref->oper_class != start_pref->oper_class || + non_pref->reason != start_pref->reason || + non_pref->preference != start_pref->preference) { + if (subelement) + wpas_mbo_non_pref_chan_subelement(wpa_s, mbo, + start, i); + else + wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start, + i); + + if (!non_pref) + return; + + start = i; + start_pref = non_pref; + } + } +} + + +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) +{ + struct wpabuf *mbo; + int res; + + if (len < MBO_IE_HEADER + 3 + 7) + return 0; + + /* Leave room for the MBO IE header */ + mbo = wpabuf_alloc(len - MBO_IE_HEADER); + if (!mbo) + return 0; + + /* Add non-preferred channels attribute */ + wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0); + + /* + * Send cellular capabilities attribute even if AP does not advertise + * cellular capabilities. + */ + wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA); + wpabuf_put_u8(mbo, 1); + wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa); + + res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo)); + if (!res) + wpa_printf(MSG_ERROR, "Failed to add MBO IE"); + + wpabuf_free(mbo); + return res; +} + + +static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s, + const u8 *data, size_t len) +{ + struct wpabuf *buf; + int res; + + /* + * Send WNM-Notification Request frame only in case of a change in + * non-preferred channels list during association, if the AP supports + * MBO. + */ + if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss || + !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) + return; + + buf = wpabuf_alloc(4 + len); + if (!buf) + return; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ); + wpa_s->mbo_wnm_token++; + if (wpa_s->mbo_wnm_token == 0) + wpa_s->mbo_wnm_token++; + wpabuf_put_u8(buf, wpa_s->mbo_wnm_token); + wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */ + + wpabuf_put_data(buf, data, len); + + res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(buf), wpabuf_len(buf), 0); + if (res < 0) + wpa_printf(MSG_DEBUG, + "Failed to send WNM-Notification Request frame with non-preferred channel list"); + + wpabuf_free(buf); +} + + +static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(512); + if (!buf) + return; + + wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1); + wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf), + wpabuf_len(buf)); + wpabuf_free(buf); +} + + +static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a, + struct wpa_mbo_non_pref_channel *b) +{ + return a->oper_class == b->oper_class && a->chan == b->chan; +} + + +/* + * wpa_non_pref_chan_cmp - Compare two channels for sorting + * + * In MBO IE non-preferred channel subelement we can put many channels in an + * attribute if they are in the same operating class and have the same + * preference and reason. To make it easy for the functions that build + * the IE attributes and WNM Request subelements, save the channels sorted + * by their oper_class and reason. + */ +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; + if (a->reason != b->reason) + return a->reason - b->reason; + return a->preference - b->preference; +} + + +int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, + const char *non_pref_chan) +{ + char *cmd, *token, *context = NULL; + struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans; + size_t num = 0, size = 0; + unsigned i; + + wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%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. + */ + if (!non_pref_chan || os_strlen(non_pref_chan) < 10) + goto update; + + cmd = os_strdup(non_pref_chan); + if (!cmd) + return -1; + + while ((token = str_token(cmd, " ", &context))) { + struct wpa_mbo_non_pref_channel *chan; + int ret; + unsigned int _oper_class; + unsigned int _chan; + unsigned int _preference; + unsigned int _reason; + + if (num == size) { + size = size ? size * 2 : 1; + tmp_chans = os_realloc_array(chans, size, + sizeof(*chans)); + if (!tmp_chans) { + wpa_printf(MSG_ERROR, + "Couldn't reallocate non_pref_chan"); + goto fail; + } + chans = tmp_chans; + } + + chan = &chans[num]; + + ret = sscanf(token, "%u:%u:%u:%u", &_oper_class, + &_chan, &_preference, &_reason); + if (ret != 4 || + _oper_class > 255 || _chan > 255 || + _preference > 255 || _reason > 65535 ) { + wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s", + token); + goto fail; + } + chan->oper_class = _oper_class; + chan->chan = _chan; + chan->preference = _preference; + chan->reason = _reason; + + if (wpas_mbo_validate_non_pref_chan(chan->oper_class, + chan->chan, chan->reason)) { + wpa_printf(MSG_ERROR, + "Invalid non_pref_chan: oper class %d chan %d reason %d", + chan->oper_class, chan->chan, chan->reason); + goto fail; + } + + for (i = 0; i < num; i++) + if (wpa_non_pref_chan_is_eq(chan, &chans[i])) + break; + if (i != num) { + wpa_printf(MSG_ERROR, + "oper class %d chan %d is duplicated", + chan->oper_class, chan->chan); + goto fail; + } + + num++; + } + + os_free(cmd); + + if (chans) { + qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel), + wpa_non_pref_chan_cmp); + } + +update: + os_free(wpa_s->non_pref_chan); + wpa_s->non_pref_chan = chans; + wpa_s->non_pref_chan_num = num; + wpas_mbo_non_pref_chan_changed(wpa_s); + + return 0; + +fail: + os_free(chans); + os_free(cmd); + return -1; +} + + +void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie) +{ + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(ie, 7); + 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 (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; +} + + +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; + u8 id, elen; + u16 disallowed_sec = 0; + + if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA || + mbo_ie[3] != MBO_OUI_TYPE) + return; + + pos = mbo_ie + 4; + len -= 4; + + while (len >= 2) { + id = *pos++; + elen = *pos++; + len -= 2; + + if (elen > len) + goto fail; + + switch (id) { + case MBO_ATTR_ID_CELL_DATA_PREF: + if (elen != 1) + goto fail; + + if (wpa_s->conf->mbo_cell_capa == + MBO_CELL_CAPA_AVAILABLE) + cell_pref = pos; + else + wpa_printf(MSG_DEBUG, + "MBO: Station does not support Cellular data connection"); + break; + case MBO_ATTR_ID_TRANSITION_REASON: + if (elen != 1) + goto fail; + + reason = pos; + break; + case MBO_ATTR_ID_ASSOC_RETRY_DELAY: + if (elen != 2) + goto fail; + + if (wpa_s->wnm_mode & + WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { + wpa_printf(MSG_DEBUG, + "MBO: Unexpected association retry delay, BSS is terminating"); + goto fail; + } else if (wpa_s->wnm_mode & + WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { + disallowed_sec = WPA_GET_LE16(pos); + } else { + wpa_printf(MSG_DEBUG, + "MBO: Association retry delay attribute not in disassoc imminent mode"); + } + + break; + case MBO_ATTR_ID_AP_CAPA_IND: + case MBO_ATTR_ID_NON_PREF_CHAN_REPORT: + case MBO_ATTR_ID_CELL_DATA_CAPA: + case MBO_ATTR_ID_ASSOC_DISALLOW: + case MBO_ATTR_ID_TRANSITION_REJECT_REASON: + wpa_printf(MSG_DEBUG, + "MBO: Attribute %d should not be included in BTM Request frame", + id); + break; + default: + wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u", + id); + return; + } + + pos += elen; + len -= elen; + } + + if (cell_pref) + wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u", + *cell_pref); + + if (reason) + wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u", + *reason); + + if (disallowed_sec && wpa_s->current_bss) + wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid, + disallowed_sec); + + return; +fail: + wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)", + id, elen, len); +} + + +size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, + size_t len, + enum mbo_transition_reject_reason reason) +{ + u8 reject_attr[3]; + + reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON; + reject_attr[1] = 1; + reject_attr[2] = reason; + + return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr)); +} + + +void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa) +{ + u8 cell_capa[7]; + + if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) { + wpa_printf(MSG_DEBUG, + "MBO: Cellular capability already set to %u", + mbo_cell_capa); + return; + } + + wpa_s->conf->mbo_cell_capa = mbo_cell_capa; + + cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC; + cell_capa[1] = 5; /* Length */ + WPA_PUT_BE24(cell_capa + 2, OUI_WFA); + cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA; + cell_capa[6] = mbo_cell_capa; + + wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7); + wpa_supplicant_set_default_scan_ies(wpa_s); +} + + +struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + struct wpabuf *anqp_buf; + u8 *len_pos; + + if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) { + wpa_printf(MSG_INFO, "MBO: " MACSTR + " does not support MBO - cannot request MBO ANQP elements from it", + MAC2STR(bss->bssid)); + return NULL; + } + + anqp_buf = wpabuf_alloc(10); + if (!anqp_buf) + return NULL; + + len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC); + 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); + gas_anqp_set_element_len(anqp_buf, len_pos); + + return anqp_buf; +} diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c index 77f708b..d67d3b2 100644 --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c @@ -66,9 +66,11 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s, } -static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid) +static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) { struct mesh_conf *conf; + int cipher; conf = os_zalloc(sizeof(struct mesh_conf)); if (!conf) @@ -82,6 +84,33 @@ static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid) MESH_CONF_SEC_AMPE; else conf->security |= MESH_CONF_SEC_NONE; + conf->ieee80211w = ssid->ieee80211w; + if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) { + if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP) + conf->ieee80211w = wpa_s->conf->pmf; + else + conf->ieee80211w = NO_MGMT_FRAME_PROTECTION; + } + + cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0); + if (cipher < 0 || cipher == WPA_CIPHER_TKIP) { + wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher"); + os_free(conf); + return NULL; + } + conf->pairwise_cipher = cipher; + + cipher = wpa_pick_group_cipher(ssid->group_cipher); + if (cipher < 0 || cipher == WPA_CIPHER_TKIP || + cipher == WPA_CIPHER_GTK_NOT_USED) { + wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher"); + os_free(conf); + return NULL; + } + + conf->group_cipher = cipher; + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) + conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; /* defaults */ conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP; @@ -149,6 +178,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data)); if (!bss) goto out_free; + dl_list_init(&bss->nr_db); os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN); bss->driver = wpa_s->driver; @@ -175,24 +205,41 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, wpa_s->conf->dot11RSNASAERetransPeriod; os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface)); - mconf = mesh_config_create(ssid); + mconf = mesh_config_create(wpa_s, ssid); if (!mconf) goto out_free; ifmsh->mconf = mconf; /* need conf->hw_mode for supported rates. */ - if (ssid->frequency == 0) { - conf->hw_mode = HOSTAPD_MODE_IEEE80211G; - conf->channel = 1; - } else { - conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, - &conf->channel); - } + conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel); if (conf->hw_mode == NUM_HOSTAPD_MODES) { wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz", ssid->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; + switch (conf->vht_oper_chwidth) { + case VHT_CHANWIDTH_80MHZ: + case VHT_CHANWIDTH_80P80MHZ: + ieee80211_freq_to_chan( + ssid->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, + &conf->vht_oper_centr_freq_seg0_idx); + conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2; + conf->vht_oper_centr_freq_seg0_idx += 40 / 5; + break; + } + ieee80211_freq_to_chan(ssid->vht_center_freq2, + &conf->vht_oper_centr_freq_seg1_idx); + } if (ssid->mesh_basic_rates == NULL) { /* @@ -318,16 +365,47 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, wpa_supplicant_mesh_deinit(wpa_s); + wpa_s->pairwise_cipher = WPA_CIPHER_NONE; + 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; + if (wpa_s->mesh_vht_enabled) { + ssid->vht = 1; + switch (params.freq.bandwidth) { + case 80: + if (params.freq.center_freq2) { + ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ; + ssid->vht_center_freq2 = + params.freq.center_freq2; + } else { + ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ; + } + break; + case 160: + ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ; + break; + default: + ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT; + break; + } + } if (ssid->beacon_int > 0) params.beacon_int = ssid->beacon_int; else if (wpa_s->conf->beacon_int > 0) params.beacon_int = wpa_s->conf->beacon_int; - params.max_peer_links = wpa_s->conf->max_peer_links; + if (ssid->dtim_period > 0) + 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; if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH; @@ -337,10 +415,10 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, if (wpa_s->conf->user_mpm) { params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM; - params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS; + params.conf.auto_plinks = 0; } else { params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM; - params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS; + params.conf.auto_plinks = 1; } params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity; @@ -351,21 +429,32 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, 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\n", 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); + out: return ret; } @@ -535,9 +624,22 @@ int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname, if (!mesh_wpa_s) { wpa_printf(MSG_ERROR, "mesh: Failed to create new wpa_supplicant interface"); - wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0); + wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname); return -1; } mesh_wpa_s->mesh_if_created = 1; return 0; } + + +int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr) +{ + return mesh_mpm_close_peer(wpa_s, addr); +} + + +int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr, + int duration) +{ + return mesh_mpm_connect_peer(wpa_s, addr, duration); +} diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h index 3cb7f1b..7317083 100644 --- a/wpa_supplicant/mesh.h +++ b/wpa_supplicant/mesh.h @@ -18,6 +18,9 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end); int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname, size_t len); +int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr); +int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr, + int duration); #ifdef CONFIG_MESH diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c index f81b88c..d14c7e3 100644 --- a/wpa_supplicant/mesh_mpm.c +++ b/wpa_supplicant/mesh_mpm.c @@ -14,17 +14,18 @@ #include "ap/hostapd.h" #include "ap/sta_info.h" #include "ap/ieee802_11.h" +#include "ap/wpa_auth.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "mesh_mpm.h" #include "mesh_rsn.h" struct mesh_peer_mgmt_ie { - const u8 *proto_id; - const u8 *llid; - const u8 *plid; - const u8 *reason; - const u8 *pmk; + const u8 *proto_id; /* Mesh Peering Protocol Identifier (2 octets) */ + const u8 *llid; /* Local Link ID (2 octets) */ + const u8 *plid; /* Peer Link ID (conditional, 2 octets) */ + const u8 *reason; /* Reason Code (conditional, 2 octets) */ + const u8 *chosen_pmk; /* Chosen PMK (optional, 16 octets) */ }; static void plink_timer(void *eloop_ctx, void *user_data); @@ -34,18 +35,17 @@ enum plink_event { PLINK_UNDEFINED, OPN_ACPT, OPN_RJCT, - OPN_IGNR, CNF_ACPT, CNF_RJCT, - CNF_IGNR, CLS_ACPT, - CLS_IGNR + REQ_RJCT }; static const char * const mplstate[] = { - [PLINK_LISTEN] = "LISTEN", - [PLINK_OPEN_SENT] = "OPEN_SENT", - [PLINK_OPEN_RCVD] = "OPEN_RCVD", + [0] = "UNINITIALIZED", + [PLINK_IDLE] = "IDLE", + [PLINK_OPN_SNT] = "OPN_SNT", + [PLINK_OPN_RCVD] = "OPN_RCVD", [PLINK_CNF_RCVD] = "CNF_RCVD", [PLINK_ESTAB] = "ESTAB", [PLINK_HOLDING] = "HOLDING", @@ -56,12 +56,10 @@ static const char * const mplevent[] = { [PLINK_UNDEFINED] = "UNDEFINED", [OPN_ACPT] = "OPN_ACPT", [OPN_RJCT] = "OPN_RJCT", - [OPN_IGNR] = "OPN_IGNR", [CNF_ACPT] = "CNF_ACPT", [CNF_RJCT] = "CNF_RJCT", - [CNF_IGNR] = "CNF_IGNR", [CLS_ACPT] = "CLS_ACPT", - [CLS_IGNR] = "CLS_IGNR" + [REQ_RJCT] = "REQ_RJCT", }; @@ -72,10 +70,10 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s, { os_memset(mpm_ie, 0, sizeof(*mpm_ie)); - /* remove optional PMK at end */ - if (len >= 16) { - len -= 16; - mpm_ie->pmk = ie + len - 16; + /* Remove optional Chosen PMK field at end */ + if (len >= SAE_PMKID_LEN) { + mpm_ie->chosen_pmk = ie + len - SAE_PMKID_LEN; + len -= SAE_PMKID_LEN; } if ((action_field == PLINK_OPEN && len != 4) || @@ -101,8 +99,8 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s, len -= 2; } - /* plid, present for confirm, and possibly close */ - if (len) + /* Peer Link ID, present for confirm, and possibly close */ + if (len >= 2) mpm_ie->plid = ie; return 0; @@ -193,12 +191,13 @@ static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s, sta->my_lid = llid; sta->peer_lid = 0; + sta->peer_aid = 0; /* * We do not use wpa_mesh_set_plink_state() here because there is no * entry in kernel yet. */ - sta->plink_state = PLINK_LISTEN; + sta->plink_state = PLINK_IDLE; } @@ -212,9 +211,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, struct hostapd_data *bss = ifmsh->bss[0]; struct mesh_conf *conf = ifmsh->mconf; u8 supp_rates[2 + 2 + 32]; -#ifdef CONFIG_IEEE80211N - u8 ht_capa_oper[2 + 26 + 2 + 22]; -#endif /* CONFIG_IEEE80211N */ u8 *pos, *cat; u8 ie_len, add_plid = 0; int ret; @@ -239,6 +235,12 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, 2 + 22; /* HT operation */ } #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_IEEE80211AC + if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) { + buf_len += 2 + 12 + /* VHT Capabilities */ + 2 + 5; /* VHT Operation */ + } +#endif /* CONFIG_IEEE80211AC */ if (type != PLINK_CLOSE) buf_len += conf->rsn_ie_len; /* RSN IE */ @@ -258,7 +260,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, /* aid */ if (type == PLINK_CONFIRM) - wpabuf_put_le16(buf, sta->peer_lid); + wpabuf_put_le16(buf, sta->aid); /* IE: supp + ext. supp rates */ pos = hostapd_eid_supp_rates(bss, supp_rates); @@ -285,7 +287,8 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, /* TODO: Add Connected to Mesh Gate/AS subfields */ wpabuf_put_u8(buf, info); /* always forwarding & accepting plinks for now */ - wpabuf_put_u8(buf, 0x1 | 0x8); + wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER | + MESH_CAP_FORWARDING); } else { /* Peer closing frame */ /* IE: Mesh ID */ wpabuf_put_u8(buf, WLAN_EID_MESH_ID); @@ -334,11 +337,22 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211N if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) { + u8 ht_capa_oper[2 + 26 + 2 + 22]; + pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper); pos = hostapd_eid_ht_operation(bss, pos); wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper); } #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_IEEE80211AC + if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) { + u8 vht_capa_oper[2 + 12 + 2 + 5]; + + pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper, 0); + pos = hostapd_eid_vht_operation(bss, pos); + wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper); + } +#endif /* CONFIG_IEEE80211AC */ if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) { wpa_msg(wpa_s, MSG_INFO, @@ -346,6 +360,9 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, goto fail; } + wpa_msg(wpa_s, MSG_DEBUG, "Mesh MPM: Sending peering frame type %d to " + MACSTR " (my_lid=0x%x peer_lid=0x%x)", + type, MAC2STR(sta->addr), sta->my_lid, sta->peer_lid); ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, sta->addr, wpa_s->own_addr, wpa_s->own_addr, wpabuf_head(buf), wpabuf_len(buf), 0); @@ -366,15 +383,17 @@ void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct hostapd_sta_add_params params; int ret; + wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " from %s into %s", + MAC2STR(sta->addr), mplstate[sta->plink_state], + mplstate[state]); sta->plink_state = state; os_memset(¶ms, 0, sizeof(params)); params.addr = sta->addr; params.plink_state = state; + params.peer_aid = sta->peer_aid; params.set = 1; - wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s", - MAC2STR(sta->addr), mplstate[state]); ret = wpa_drv_sta_add(wpa_s, ¶ms); if (ret) { wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR @@ -400,10 +419,11 @@ static void plink_timer(void *eloop_ctx, void *user_data) struct sta_info *sta = user_data; u16 reason = 0; struct mesh_conf *conf = wpa_s->ifmsh->mconf; + struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; switch (sta->plink_state) { - case PLINK_OPEN_RCVD: - case PLINK_OPEN_SENT: + case PLINK_OPN_RCVD: + case PLINK_OPN_SNT: /* retry timer */ if (sta->mpm_retries < conf->dot11MeshMaxRetries) { eloop_register_timeout( @@ -429,6 +449,13 @@ static void plink_timer(void *eloop_ctx, void *user_data) break; case PLINK_HOLDING: /* holding timer */ + + if (sta->mesh_sae_pmksa_caching) { + wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR + " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it", + MAC2STR(sta->addr)); + wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); + } mesh_mpm_fsm_restart(wpa_s, sta); break; default: @@ -453,8 +480,8 @@ mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta, } -int mesh_mpm_plink_close(struct hostapd_data *hapd, - struct sta_info *sta, void *ctx) +static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta, + void *ctx) { struct wpa_supplicant *wpa_s = ctx; int reason = WLAN_REASON_MESH_PEERING_CANCELLED; @@ -472,6 +499,85 @@ int mesh_mpm_plink_close(struct hostapd_data *hapd, } +int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr) +{ + struct hostapd_data *hapd; + struct sta_info *sta; + + if (!wpa_s->ifmsh) { + wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet"); + return -1; + } + + hapd = wpa_s->ifmsh->bss[0]; + sta = ap_get_sta(hapd, addr); + if (!sta) { + wpa_msg(wpa_s, MSG_INFO, "No such mesh peer"); + return -1; + } + + return mesh_mpm_plink_close(hapd, sta, wpa_s) == 0 ? 0 : -1; +} + + +static void peer_add_timer(void *eloop_ctx, void *user_data) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; + + os_memset(hapd->mesh_required_peer, 0, ETH_ALEN); +} + + +int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr, + int duration) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + struct hostapd_data *hapd; + struct sta_info *sta; + struct mesh_conf *conf; + + if (!wpa_s->ifmsh) { + wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet"); + return -1; + } + + if (!ssid || !ssid->no_auto_peer) { + wpa_msg(wpa_s, MSG_INFO, + "This command is available only with no_auto_peer mesh network"); + return -1; + } + + hapd = wpa_s->ifmsh->bss[0]; + conf = wpa_s->ifmsh->mconf; + + sta = ap_get_sta(hapd, addr); + if (!sta) { + wpa_msg(wpa_s, MSG_INFO, "No such mesh peer"); + return -1; + } + + if ((PLINK_OPN_SNT <= sta->plink_state && + sta->plink_state <= PLINK_ESTAB) || + (sta->sae && sta->sae->state > SAE_NOTHING)) { + wpa_msg(wpa_s, MSG_INFO, + "Specified peer is connecting/connected"); + return -1; + } + + if (conf->security == MESH_CONF_SEC_NONE) { + mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT); + } else { + mesh_rsn_auth_sae_sta(wpa_s, sta); + os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN); + eloop_register_timeout(duration == -1 ? 10 : duration, 0, + peer_add_timer, wpa_s, NULL); + } + + return 0; +} + + void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh) { struct hostapd_data *hapd = ifmsh->bss[0]; @@ -481,6 +587,7 @@ void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh) hapd->num_plinks = 0; hostapd_free_stas(hapd); + eloop_cancel_timeout(peer_add_timer, wpa_s, NULL); } @@ -522,7 +629,7 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr) if (!sta->my_lid) mesh_mpm_init_link(wpa_s, sta); - mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT); + mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT); } /* @@ -541,6 +648,14 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, struct sta_info *sta; int ret; + if (elems->mesh_config_len >= 7 && + !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) { + wpa_msg(wpa_s, MSG_DEBUG, + "mesh: Ignore a crowded peer " MACSTR, + MAC2STR(addr)); + return NULL; + } + sta = ap_get_sta(data, addr); if (!sta) { sta = ap_sta_add(data, addr); @@ -548,28 +663,45 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, return NULL; } + /* Set WMM by default since Mesh STAs are QoS STAs */ + sta->flags |= WLAN_STA_WMM; + /* initialize sta */ if (copy_supp_rates(wpa_s, sta, elems)) { ap_free_sta(data, sta); return NULL; } - mesh_mpm_init_link(wpa_s, sta); + if (!sta->my_lid) + mesh_mpm_init_link(wpa_s, sta); #ifdef CONFIG_IEEE80211N copy_sta_ht_capab(data, sta, elems->ht_capabilities); update_ht_state(data, sta); #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_IEEE80211AC + copy_sta_vht_capab(data, sta, elems->vht_capabilities); + set_sta_vht_opmode(data, sta, elems->vht_opmode_notif); +#endif /* CONFIG_IEEE80211AC */ + + if (hostapd_get_aid(data, sta) < 0) { + wpa_msg(wpa_s, MSG_ERROR, "No AIDs available"); + ap_free_sta(data, sta); + return NULL; + } + /* insert into driver */ os_memset(¶ms, 0, sizeof(params)); params.supp_rates = sta->supported_rates; params.supp_rates_len = sta->supported_rates_len; params.addr = addr; params.plink_state = sta->plink_state; - params.aid = sta->peer_lid; + params.aid = sta->aid; + params.peer_aid = sta->peer_aid; params.listen_interval = 100; params.ht_capabilities = sta->ht_capabilities; + params.vht_capabilities = sta->vht_capabilities; params.flags |= WPA_STA_WMM; params.flags_mask |= WPA_STA_AUTHENTICATED; if (conf->security == MESH_CONF_SEC_NONE) { @@ -605,7 +737,9 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, if (!sta) return; - if (ssid && ssid->no_auto_peer) { + if (ssid && ssid->no_auto_peer && + (is_zero_ether_addr(data->mesh_required_peer) || + os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) { wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with " MACSTR " because of no_auto_peer", MAC2STR(addr)); if (data->mesh_pending_auth) { @@ -634,10 +768,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, return; } - if (conf->security == MESH_CONF_SEC_NONE) - mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT); - else + if (conf->security == MESH_CONF_SEC_NONE) { + if (sta->plink_state < PLINK_OPN_SNT || + sta->plink_state > PLINK_ESTAB) + mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT); + } else { mesh_rsn_auth_sae_sta(wpa_s, sta); + } } @@ -664,64 +801,85 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, MAC2STR(sta->addr)); if (conf->security & MESH_CONF_SEC_AMPE) { - wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0, - seq, sizeof(seq), sta->mtk, sizeof(sta->mtk)); - wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0, - seq, sizeof(seq), - sta->mgtk, sizeof(sta->mgtk)); - wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0, - seq, sizeof(seq), - sta->mgtk, sizeof(sta->mgtk)); - - wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk)); - wpa_hexdump_key(MSG_DEBUG, "mgtk:", - sta->mgtk, sizeof(sta->mgtk)); + wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len); + wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher), + sta->addr, 0, 0, seq, sizeof(seq), + sta->mtk, sta->mtk_len); + + wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC", + sta->mgtk_rsc, sizeof(sta->mgtk_rsc)); + wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK", + sta->mgtk, sta->mgtk_len); + wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher), + sta->addr, sta->mgtk_key_id, 0, + sta->mgtk_rsc, sizeof(sta->mgtk_rsc), + sta->mgtk, sta->mgtk_len); + + if (sta->igtk_len) { + wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC", + sta->igtk_rsc, sizeof(sta->igtk_rsc)); + wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK", + sta->igtk, sta->igtk_len); + wpa_drv_set_key( + wpa_s, + wpa_cipher_to_alg(conf->mgmt_group_cipher), + sta->addr, sta->igtk_key_id, 0, + sta->igtk_rsc, sizeof(sta->igtk_rsc), + sta->igtk, sta->igtk_len); + } } wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB); hapd->num_plinks++; sta->flags |= WLAN_STA_ASSOC; + sta->mesh_sae_pmksa_caching = 0; + eloop_cancel_timeout(peer_add_timer, wpa_s, NULL); + peer_add_timer(wpa_s, NULL); eloop_cancel_timeout(plink_timer, wpa_s, sta); /* Send ctrl event */ - wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR, - MAC2STR(sta->addr)); + wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR, + MAC2STR(sta->addr)); } static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, - enum plink_event event) + enum plink_event event, u16 reason) { struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; struct mesh_conf *conf = wpa_s->ifmsh->mconf; - u16 reason = 0; wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s", MAC2STR(sta->addr), mplstate[sta->plink_state], mplevent[event]); switch (sta->plink_state) { - case PLINK_LISTEN: + case PLINK_IDLE: switch (event) { case CLS_ACPT: mesh_mpm_fsm_restart(wpa_s, sta); break; case OPN_ACPT: - mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD); + mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD); mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0); break; + case REQ_RJCT: + mesh_mpm_send_plink_action(wpa_s, sta, + PLINK_CLOSE, reason); + break; default: break; } break; - case PLINK_OPEN_SENT: + case PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: - reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; + if (!reason) + reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; /* fall-through */ case CLS_ACPT: wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); @@ -736,12 +894,13 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, break; case OPN_ACPT: /* retry timer is left untouched */ - wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD); + wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD); mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0); break; case CNF_ACPT: wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD); + eloop_cancel_timeout(plink_timer, wpa_s, sta); eloop_register_timeout( conf->dot11MeshConfirmTimeout / 1000, (conf->dot11MeshConfirmTimeout % 1000) * 1000, @@ -751,11 +910,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, break; } break; - case PLINK_OPEN_RCVD: + case PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: - reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; + if (!reason) + reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; /* fall-through */ case CLS_ACPT: wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); @@ -786,7 +946,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, switch (event) { case OPN_RJCT: case CNF_RJCT: - reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; + if (!reason) + reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; /* fall-through */ case CLS_ACPT: wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); @@ -801,6 +962,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, PLINK_CLOSE, reason); break; case OPN_ACPT: + if (conf->security & MESH_CONF_SEC_AMPE) + mesh_rsn_derive_mtk(wpa_s, sta); mesh_mpm_plink_estab(wpa_s, sta); mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0); @@ -811,9 +974,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, break; case PLINK_ESTAB: switch (event) { + case OPN_RJCT: + case CNF_RJCT: case CLS_ACPT: wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); - reason = WLAN_REASON_MESH_CLOSE_RCVD; + if (!reason) + reason = WLAN_REASON_MESH_CLOSE_RCVD; eloop_register_timeout( conf->dot11MeshHoldingTimeout / 1000, @@ -825,9 +991,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, " closed with reason %d", MAC2STR(sta->addr), reason); - wpa_msg_ctrl(wpa_s, MSG_INFO, - MESH_PEER_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); + wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); hapd->num_plinks--; @@ -875,13 +1040,14 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; struct mesh_conf *mconf = wpa_s->ifmsh->mconf; struct sta_info *sta; - u16 plid = 0, llid = 0; + u16 plid = 0, llid = 0, aid = 0; enum plink_event event; struct ieee802_11_elems elems; struct mesh_peer_mgmt_ie peer_mgmt_ie; const u8 *ies; size_t ie_len; int ret; + u16 reason = 0; if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED) return; @@ -912,7 +1078,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, ie_len -= 2; } if (action_field == PLINK_CONFIRM) { - wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies)); + aid = WPA_GET_LE16(ies); + wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid); ies += 2; /* aid */ ie_len -= 2; } @@ -956,6 +1123,10 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, llid = WPA_GET_LE16(peer_mgmt_ie.plid); wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid); + if (action_field == PLINK_CLOSE) + wpa_printf(MSG_DEBUG, "MPM: close reason=%u", + WPA_GET_LE16(peer_mgmt_ie.reason)); + sta = ap_get_sta(hapd, mgmt->sa); /* @@ -963,7 +1134,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, * open mesh, then go ahead and add the peer before proceeding. */ if (!sta && action_field == PLINK_OPEN && - !(mconf->security & MESH_CONF_SEC_AMPE)) + (!(mconf->security & MESH_CONF_SEC_AMPE) || + wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa))) sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems); if (!sta) { @@ -982,12 +1154,24 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, if (!sta->my_lid) mesh_mpm_init_link(wpa_s, sta); - if ((mconf->security & MESH_CONF_SEC_AMPE) && - mesh_rsn_process_ampe(wpa_s, sta, &elems, - &mgmt->u.action.category, - ies, ie_len)) { - wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame"); - return; + if (mconf->security & MESH_CONF_SEC_AMPE) { + int res; + + res = mesh_rsn_process_ampe(wpa_s, sta, &elems, + &mgmt->u.action.category, + peer_mgmt_ie.chosen_pmk, + ies, ie_len); + if (res) { + wpa_printf(MSG_DEBUG, + "MPM: RSN process rejected frame (res=%d)", + res); + if (action_field == PLINK_OPEN && res == -2) { + /* AES-SIV decryption failed */ + mesh_mpm_fsm(wpa_s, sta, OPN_RJCT, + WLAN_REASON_MESH_INVALID_GTK); + } + return; + } } if (sta->plink_state == PLINK_BLOCKED) { @@ -999,12 +1183,16 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, switch (action_field) { case PLINK_OPEN: if (plink_free_count(hapd) == 0) { - event = OPN_IGNR; + event = REQ_RJCT; + reason = WLAN_REASON_MESH_MAX_PEERS; wpa_printf(MSG_INFO, "MPM: Peer link num over quota(%d)", hapd->max_plinks); } else if (sta->peer_lid && sta->peer_lid != plid) { - event = OPN_IGNR; + wpa_printf(MSG_DEBUG, + "MPM: peer_lid mismatch: 0x%x != 0x%x", + sta->peer_lid, plid); + return; /* no FSM event */ } else { sta->peer_lid = plid; event = OPN_ACPT; @@ -1012,16 +1200,21 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, break; case PLINK_CONFIRM: if (plink_free_count(hapd) == 0) { - event = CNF_IGNR; + event = REQ_RJCT; + reason = WLAN_REASON_MESH_MAX_PEERS; wpa_printf(MSG_INFO, "MPM: Peer link num over quota(%d)", hapd->max_plinks); } else if (sta->my_lid != llid || (sta->peer_lid && sta->peer_lid != plid)) { - event = CNF_IGNR; + wpa_printf(MSG_DEBUG, + "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x", + sta->my_lid, llid, sta->peer_lid, plid); + return; /* no FSM event */ } else { if (!sta->peer_lid) sta->peer_lid = plid; + sta->peer_aid = aid; event = CNF_ACPT; } break; @@ -1037,12 +1230,19 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, * restarted. */ event = CLS_ACPT; - else if (sta->peer_lid != plid) - event = CLS_IGNR; - else if (peer_mgmt_ie.plid && sta->my_lid != llid) - event = CLS_IGNR; - else + else if (sta->peer_lid != plid) { + wpa_printf(MSG_DEBUG, + "MPM: peer_lid mismatch: 0x%x != 0x%x", + sta->peer_lid, plid); + return; /* no FSM event */ + } else if (peer_mgmt_ie.plid && sta->my_lid != llid) { + wpa_printf(MSG_DEBUG, + "MPM: my_lid mismatch: 0x%x != 0x%x", + sta->my_lid, llid); + return; /* no FSM event */ + } else { event = CLS_ACPT; + } break; default: /* @@ -1052,13 +1252,15 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, */ return; } - mesh_mpm_fsm(wpa_s, sta, event); + mesh_mpm_fsm(wpa_s, sta, event, reason); } /* called by ap_free_sta */ -void mesh_mpm_free_sta(struct sta_info *sta) +void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { + if (sta->plink_state == PLINK_ESTAB) + hapd->num_plinks--; eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta); eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta); } diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h index 7ebaef0..5fc1e61 100644 --- a/wpa_supplicant/mesh_mpm.h +++ b/wpa_supplicant/mesh_mpm.h @@ -14,10 +14,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, struct ieee802_11_elems *elems); void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh); void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr); -void mesh_mpm_free_sta(struct sta_info *sta); +void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta); void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta, enum mesh_plink_state state); +int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr); +int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr, + int duration); #ifdef CONFIG_MESH diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index 747f1ae..27ab8cb 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -27,12 +27,12 @@ #define MESH_AUTH_TIMEOUT 10 #define MESH_AUTH_RETRY 3 -#define MESH_AUTH_BLOCK_DURATION 3600 void mesh_auth_timer(void *eloop_ctx, void *user_data) { struct wpa_supplicant *wpa_s = eloop_ctx; struct sta_info *sta = user_data; + struct hostapd_data *hapd; if (sta->sae->state != SAE_ACCEPTED) { wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR @@ -43,23 +43,20 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data) if (sta->sae_auth_retry < MESH_AUTH_RETRY) { mesh_rsn_auth_sae_sta(wpa_s, sta); } else { + hapd = wpa_s->ifmsh->bss[0]; + if (sta->sae_auth_retry > MESH_AUTH_RETRY) { - ap_free_sta(wpa_s->ifmsh->bss[0], sta); + ap_free_sta(hapd, sta); return; } /* block the STA if exceeded the number of attempts */ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED); sta->sae->state = SAE_NOTHING; - if (wpa_s->mesh_auth_block_duration < - MESH_AUTH_BLOCK_DURATION) - wpa_s->mesh_auth_block_duration += 60; - eloop_register_timeout(wpa_s->mesh_auth_block_duration, - 0, mesh_auth_timer, wpa_s, sta); wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr=" MACSTR " duration=%d", MAC2STR(sta->addr), - wpa_s->mesh_auth_block_duration); + hapd->conf->ap_max_inactivity); } sta->sae_auth_retry++; } @@ -139,7 +136,8 @@ static int auth_start_ampe(void *ctx, const u8 *addr) } -static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr) +static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, + enum mfp_options ieee80211w) { struct wpa_auth_config conf; struct wpa_auth_callbacks cb; @@ -148,13 +146,18 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr) wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); os_memset(&conf, 0, sizeof(conf)); - conf.wpa = 2; + conf.wpa = WPA_PROTO_RSN; conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE; - conf.wpa_pairwise = WPA_CIPHER_CCMP; - conf.rsn_pairwise = WPA_CIPHER_CCMP; - conf.wpa_group = WPA_CIPHER_CCMP; + conf.wpa_pairwise = rsn->pairwise_cipher; + conf.rsn_pairwise = rsn->pairwise_cipher; + conf.wpa_group = rsn->group_cipher; conf.eapol_version = 0; conf.wpa_group_rekey = -1; +#ifdef CONFIG_IEEE80211W + conf.ieee80211w = ieee80211w; + if (ieee80211w != NO_MGMT_FRAME_PROTECTION) + conf.group_mgmt_cipher = rsn->mgmt_group_cipher; +#endif /* CONFIG_IEEE80211W */ os_memset(&cb, 0, sizeof(cb)); cb.ctx = rsn; @@ -170,18 +173,34 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr) } /* TODO: support rekeying */ - if (random_get_bytes(rsn->mgtk, 16) < 0) { - wpa_deinit(rsn->auth); + rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group); + if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0) return -1; - } + rsn->mgtk_key_id = 1; - /* group mgmt */ - wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1, - seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk)); +#ifdef CONFIG_IEEE80211W + if (ieee80211w != NO_MGMT_FRAME_PROTECTION) { + rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher); + if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0) + return -1; + rsn->igtk_key_id = 4; + + /* group mgmt */ + wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK", + rsn->igtk, rsn->igtk_len); + wpa_drv_set_key(rsn->wpa_s, + wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL, + rsn->igtk_key_id, 1, + seq, sizeof(seq), rsn->igtk, rsn->igtk_len); + } +#endif /* CONFIG_IEEE80211W */ /* group privacy / data frames */ - wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1, - seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk)); + wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK", + rsn->mgtk, rsn->mgtk_len); + wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL, + rsn->mgtk_key_id, 1, seq, sizeof(seq), + rsn->mgtk, rsn->mgtk_len); return 0; } @@ -190,6 +209,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr) static void mesh_rsn_deinit(struct mesh_rsn *rsn) { os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk)); + rsn->mgtk_len = 0; + os_memset(rsn->igtk, 0, sizeof(rsn->igtk)); + rsn->igtk_len = 0; if (rsn->auth) wpa_deinit(rsn->auth); } @@ -207,8 +229,12 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, if (mesh_rsn == NULL) return NULL; mesh_rsn->wpa_s = wpa_s; + mesh_rsn->pairwise_cipher = conf->pairwise_cipher; + mesh_rsn->group_cipher = conf->group_cipher; + mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher; - if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) { + if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr, + conf->ieee80211w) < 0) { mesh_rsn_deinit(mesh_rsn); os_free(mesh_rsn); return NULL; @@ -291,6 +317,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, { struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; struct wpa_ssid *ssid = wpa_s->current_ssid; + struct rsn_pmksa_cache_entry *pmksa; unsigned int rnd; int ret; @@ -306,6 +333,29 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, return -1; } + pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr); + if (pmksa) { + if (!sta->wpa_sm) + sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, + sta->addr, NULL); + if (!sta->wpa_sm) { + wpa_printf(MSG_ERROR, + "mesh: Failed to initialize RSN state machine"); + return -1; + } + + wpa_printf(MSG_DEBUG, + "AUTH: Mesh PMKSA cache entry found for " MACSTR + " - try to use PMKSA caching instead of new SAE authentication", + MAC2STR(sta->addr)); + wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth, + sta->sae->pmkid, sta->sae->pmk); + sae_accept_sta(hapd, sta); + sta->mesh_sae_pmksa_caching = 1; + return 0; + } + sta->mesh_sae_pmksa_caching = 0; + if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta)) return -1; @@ -313,7 +363,6 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, "AUTH: started authentication with SAE peer: " MACSTR, MAC2STR(sta->addr)); - wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); ret = auth_sae_init_committed(hapd, sta); if (ret) return ret; @@ -328,10 +377,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid) { - /* don't expect wpa auth to cache the pmkid for now */ - rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr, - sta->addr, pmkid, - wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm))); + os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN); } @@ -340,18 +386,27 @@ mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta) { u8 *myaddr = rsn->wpa_s->own_addr; u8 *peer = sta->addr; - u8 *addr1 = peer, *addr2 = myaddr; - u8 context[AES_BLOCK_SIZE]; + u8 *addr1, *addr2; + u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context; - /* SAE */ - RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP)); + /* + * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite || + * min(localMAC, peerMAC) || max(localMAC, peerMAC)) + */ + /* Selected AKM Suite: SAE */ + RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE); + ptr += RSN_SELECTOR_LEN; if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) { addr1 = myaddr; addr2 = peer; + } else { + addr1 = peer; + addr2 = myaddr; } - os_memcpy(context + 4, addr1, ETH_ALEN); - os_memcpy(context + 10, addr2, ETH_ALEN); + os_memcpy(ptr, addr1, ETH_ALEN); + ptr += ETH_ALEN; + os_memcpy(ptr, addr2, ETH_ALEN); sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation", context, sizeof(context), sta->aek, sizeof(sta->aek)); @@ -363,40 +418,44 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta) { u8 *ptr; u8 *min, *max; - u16 min_lid, max_lid; - size_t nonce_len = sizeof(sta->my_nonce); - size_t lid_len = sizeof(sta->my_lid); u8 *myaddr = wpa_s->own_addr; u8 *peer = sta->addr; - /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */ - u8 context[64 + 4 + 4 + 12]; - + u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN]; + + /* + * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce, + * peerNonce) || max(localNonce, peerNonce) || min(localLinkID, + * peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite || + * min(localMAC, peerMAC) || max(localMAC, peerMAC)) + */ ptr = context; - if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) { + if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) { min = sta->my_nonce; max = sta->peer_nonce; } else { min = sta->peer_nonce; max = sta->my_nonce; } - os_memcpy(ptr, min, nonce_len); - os_memcpy(ptr + nonce_len, max, nonce_len); - ptr += 2 * nonce_len; + os_memcpy(ptr, min, WPA_NONCE_LEN); + ptr += WPA_NONCE_LEN; + os_memcpy(ptr, max, WPA_NONCE_LEN); + ptr += WPA_NONCE_LEN; if (sta->my_lid < sta->peer_lid) { - min_lid = host_to_le16(sta->my_lid); - max_lid = host_to_le16(sta->peer_lid); + WPA_PUT_LE16(ptr, sta->my_lid); + ptr += 2; + WPA_PUT_LE16(ptr, sta->peer_lid); + ptr += 2; } else { - min_lid = host_to_le16(sta->peer_lid); - max_lid = host_to_le16(sta->my_lid); + WPA_PUT_LE16(ptr, sta->peer_lid); + ptr += 2; + WPA_PUT_LE16(ptr, sta->my_lid); + ptr += 2; } - os_memcpy(ptr, &min_lid, lid_len); - os_memcpy(ptr + lid_len, &max_lid, lid_len); - ptr += 2 * lid_len; - /* SAE */ - RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP)); - ptr += 4; + /* Selected AKM Suite: SAE */ + RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE); + ptr += RSN_SELECTOR_LEN; if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) { min = myaddr; @@ -406,22 +465,24 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta) max = myaddr; } os_memcpy(ptr, min, ETH_ALEN); - os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN); + ptr += ETH_ALEN; + os_memcpy(ptr, max, ETH_ALEN); - sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), + sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher); + sha256_prf(sta->sae->pmk, SAE_PMK_LEN, "Temporal Key Derivation", context, sizeof(context), - sta->mtk, sizeof(sta->mtk)); + sta->mtk, sta->mtk_len); return 0; } void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta) { - if (random_get_bytes(sta->my_nonce, 32) < 0) { + if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) { wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce"); /* TODO: How to handle this more cleanly? */ } - os_memset(sta->peer_nonce, 0, 32); + os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN); mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta); } @@ -437,65 +498,94 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta, { struct ieee80211_ampe_ie *ampe; u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf); - u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload; + u8 *ampe_ie, *pos, *mic_payload; const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat }; const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat }; int ret = 0; + size_t len; + + len = sizeof(*ampe); + if (cat[1] == PLINK_OPEN) + len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4; +#ifdef CONFIG_IEEE80211W + if (cat[1] == PLINK_OPEN && rsn->igtk_len) + len += 2 + 6 + rsn->igtk_len; +#endif /* CONFIG_IEEE80211W */ - if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) { + if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) { wpa_printf(MSG_ERROR, "protect frame: buffer too small"); return -EINVAL; } - ampe_ie = os_zalloc(2 + sizeof(*ampe)); + ampe_ie = os_zalloc(2 + len); if (!ampe_ie) { wpa_printf(MSG_ERROR, "protect frame: out of memory"); return -ENOMEM; } - mic_ie = os_zalloc(2 + AES_BLOCK_SIZE); - if (!mic_ie) { - wpa_printf(MSG_ERROR, "protect frame: out of memory"); - ret = -ENOMEM; - goto free; - } - /* IE: AMPE */ ampe_ie[0] = WLAN_EID_AMPE; - ampe_ie[1] = sizeof(*ampe); + ampe_ie[1] = len; ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2); RSN_SELECTOR_PUT(ampe->selected_pairwise_suite, - wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP)); - os_memcpy(ampe->local_nonce, sta->my_nonce, 32); - os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32); - /* incomplete: see 13.5.4 */ + RSN_CIPHER_SUITE_CCMP); + os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN); + os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN); + + pos = (u8 *) (ampe + 1); + if (cat[1] != PLINK_OPEN) + goto skip_keys; + + /* TODO: Key Replay Counter[8] optionally for + * Mesh Group Key Inform/Acknowledge frames */ + /* TODO: static mgtk for now since we don't support rekeying! */ - os_memcpy(ampe->mgtk, rsn->mgtk, 16); - /* TODO: Populate Key RSC */ - /* expire in 13 decades or so */ - os_memset(ampe->key_expiration, 0xff, 4); + /* + * GTKdata[variable]: + * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4] + */ + os_memcpy(pos, rsn->mgtk, rsn->mgtk_len); + pos += rsn->mgtk_len; + wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos); + pos += WPA_KEY_RSC_LEN; + /* Use fixed GTKExpirationTime for now */ + WPA_PUT_LE32(pos, 0xffffffff); + pos += 4; + +#ifdef CONFIG_IEEE80211W + /* + * IGTKdata[variable]: + * Key ID[2], IPN[6], IGTK[variable] + */ + if (rsn->igtk_len) { + WPA_PUT_LE16(pos, rsn->igtk_key_id); + pos += 2; + wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos); + pos += 6; + os_memcpy(pos, rsn->igtk, rsn->igtk_len); + } +#endif /* CONFIG_IEEE80211W */ + +skip_keys: + wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element", + ampe_ie, 2 + len); /* IE: MIC */ - mic_ie[0] = WLAN_EID_MIC; - mic_ie[1] = AES_BLOCK_SIZE; - wpabuf_put_data(buf, mic_ie, 2); + wpabuf_put_u8(buf, WLAN_EID_MIC); + wpabuf_put_u8(buf, AES_BLOCK_SIZE); /* MIC field is output ciphertext */ /* encrypt after MIC */ - mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) + - AES_BLOCK_SIZE); + mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE); - if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3, + if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3, aad, aad_len, mic_payload)) { wpa_printf(MSG_ERROR, "protect frame: failed to encrypt"); ret = -ENOMEM; - goto free; } -free: os_free(ampe_ie); - os_free(mic_ie); return ret; } @@ -503,18 +593,37 @@ free: int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, struct ieee802_11_elems *elems, const u8 *cat, + const u8 *chosen_pmk, const u8 *start, size_t elems_len) { int ret = 0; struct ieee80211_ampe_ie *ampe; - u8 null_nonce[32] = {}; + u8 null_nonce[WPA_NONCE_LEN] = {}; u8 ampe_eid; u8 ampe_ie_len; - u8 *ampe_buf, *crypt = NULL; + u8 *ampe_buf, *crypt = NULL, *pos, *end; 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 }; + 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)) { + wpa_printf(MSG_INFO, + "Mesh RSN: SAE is not prepared yet"); + return -1; + } + mesh_rsn_auth_sae_sta(wpa_s, sta); + } + + if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) { + wpa_msg(wpa_s, MSG_DEBUG, + "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)"); + return -1; + } if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) { wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie"); @@ -526,7 +635,7 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, return -1; crypt_len = elems_len - (elems->mic - start); - if (crypt_len < 2) { + if (crypt_len < 2 + AES_BLOCK_SIZE) { wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie"); return -1; } @@ -544,14 +653,19 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3, aad, aad_len, ampe_buf)) { wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!"); - ret = -1; + ret = -2; goto free; } + crypt_len -= AES_BLOCK_SIZE; + wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element", + ampe_buf, crypt_len); + ampe_eid = *ampe_buf++; ampe_ie_len = *ampe_buf++; if (ampe_eid != WLAN_EID_AMPE || + (size_t) 2 + ampe_ie_len > crypt_len || ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) { wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie"); ret = -1; @@ -559,17 +673,89 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, } ampe = (struct ieee80211_ampe_ie *) ampe_buf; - if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 && - os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) { + pos = (u8 *) (ampe + 1); + end = ampe_buf + ampe_ie_len; + if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 && + os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) { wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce"); ret = -1; goto free; } os_memcpy(sta->peer_nonce, ampe->local_nonce, sizeof(ampe->local_nonce)); - os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk)); - /* todo parse mgtk expiration */ + /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge + * frames */ + + /* + * GTKdata shall not be included in Mesh Peering Confirm. While the + * standard does not state the same about IGTKdata, that same constraint + * needs to apply for it. It makes no sense to include the keys in Mesh + * Peering Close frames either, so while the standard does not seem to + * have a shall statement for these, they are described without + * mentioning GTKdata. + * + * An earlier implementation used to add GTKdata to both Mesh Peering + * Open and Mesh Peering Confirm frames, so ignore the possibly present + * GTKdata frame without rejecting the frame as a backwards + * compatibility mechanism. + */ + if (cat[1] != PLINK_OPEN) { + if (end > pos) { + wpa_hexdump_key(MSG_DEBUG, + "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close", + pos, end - pos); + } + goto free; + } + + /* + * GTKdata[variable]: + * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4] + */ + sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */ + key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher); + if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) { + wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element"); + ret = -1; + goto free; + } + sta->mgtk_len = key_len; + os_memcpy(sta->mgtk, pos, sta->mgtk_len); + wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK", + sta->mgtk, sta->mgtk_len); + pos += sta->mgtk_len; + wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC", + pos, WPA_KEY_RSC_LEN); + os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc)); + pos += WPA_KEY_RSC_LEN; + wpa_printf(MSG_DEBUG, + "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds", + WPA_GET_LE32(pos)); + pos += 4; + +#ifdef CONFIG_IEEE80211W + /* + * IGTKdata[variable]: + * Key ID[2], IPN[6], IGTK[variable] + */ + key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher); + if (end - pos >= (int) (2 + 6 + key_len)) { + sta->igtk_key_id = WPA_GET_LE16(pos); + wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u", + sta->igtk_key_id); + pos += 2; + os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc)); + wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN", + sta->igtk_rsc, sizeof(sta->igtk_rsc)); + pos += 6; + os_memcpy(sta->igtk, pos, key_len); + sta->igtk_len = key_len; + wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK", + sta->igtk, sta->igtk_len); + } +#endif /* CONFIG_IEEE80211W */ + free: os_free(crypt); return ret; diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h index b1471b2..8775ced 100644 --- a/wpa_supplicant/mesh_rsn.h +++ b/wpa_supplicant/mesh_rsn.h @@ -12,7 +12,15 @@ struct mesh_rsn { struct wpa_supplicant *wpa_s; struct wpa_authenticator *auth; - u8 mgtk[16]; + unsigned int pairwise_cipher; + unsigned int group_cipher; + u8 mgtk[WPA_TK_MAX_LEN]; + size_t mgtk_len; + u8 mgtk_key_id; + unsigned int mgmt_group_cipher; + u8 igtk_key_id; + u8 igtk[WPA_TK_MAX_LEN]; + size_t igtk_len; #ifdef CONFIG_SAE struct wpabuf *sae_token; int sae_group_index; @@ -30,6 +38,7 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta, const u8 *cat, struct wpabuf *buf); int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, struct ieee802_11_elems *elems, const u8 *cat, + const u8 *chosen_pmk, const u8 *start, size_t elems_len); void mesh_auth_timer(void *eloop_ctx, void *user_data); diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 45d06bf..67e36ae 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -13,6 +13,7 @@ #include "config.h" #include "wpa_supplicant_i.h" #include "wps_supplicant.h" +#include "binder/binder.h" #include "dbus/dbus_common.h" #include "dbus/dbus_old.h" #include "dbus/dbus_new.h" @@ -34,6 +35,12 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global) } #endif /* CONFIG_DBUS */ +#ifdef CONFIG_BINDER + global->binder = wpas_binder_init(global); + if (!global->binder) + return -1; +#endif /* CONFIG_BINDER */ + return 0; } @@ -44,6 +51,11 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global) if (global->dbus) wpas_dbus_deinit(global->dbus); #endif /* CONFIG_DBUS */ + +#ifdef CONFIG_BINDER + if (global->binder) + wpas_binder_deinit(global->binder); +#endif /* CONFIG_BINDER */ } @@ -128,6 +140,15 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s) } +void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE); +} + + void wpas_notify_network_changed(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) @@ -647,13 +668,13 @@ 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 network_id, + struct wpa_ssid *ssid, int persistent, int client) { /* Notify a group has been started */ wpas_dbus_register_p2p_group(wpa_s, ssid); - wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id); + wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent); } diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index d9f0f5a..8cce0f3 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -23,6 +23,7 @@ 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_assoc_status_code(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); @@ -112,7 +113,7 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, u16 config_methods, unsigned int generated_pin); void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, int network_id, + struct wpa_ssid *ssid, int persistent, int client); void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s, const char *reason); diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c index 63af83a..26d41a4 100644 --- a/wpa_supplicant/offchannel.c +++ b/wpa_supplicant/offchannel.c @@ -23,8 +23,29 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src) { struct wpa_supplicant *iface; - if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) + if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) { +#ifdef CONFIG_P2P + if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent && + wpa_s->parent->ap_iface && + os_memcmp(wpa_s->parent->own_addr, + wpa_s->own_addr, ETH_ALEN) == 0 && + wpabuf_len(wpa_s->pending_action_tx) >= 2 && + *wpabuf_head_u8(wpa_s->pending_action_tx) != + WLAN_ACTION_PUBLIC) { + /* + * When P2P Device interface has same MAC address as + * the GO interface, make sure non-Public Action frames + * are sent through the GO interface. The P2P Device + * interface can only send Public Action frames. + */ + wpa_printf(MSG_DEBUG, + "P2P: Use GO interface %s instead of interface %s for Action TX", + wpa_s->parent->ifname, wpa_s->ifname); + return wpa_s->parent; + } +#endif /* CONFIG_P2P */ return wpa_s; + } /* * Try to find a group interface that matches with the source address. @@ -118,8 +139,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx) } wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to " - MACSTR " using interface %s", - MAC2STR(wpa_s->pending_action_dst), iface->ifname); + MACSTR " using interface %s (pending_action_tx=%p)", + MAC2STR(wpa_s->pending_action_dst), iface->ifname, + wpa_s->pending_action_tx); res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0, wpa_s->pending_action_dst, wpa_s->pending_action_src, @@ -183,8 +205,12 @@ void offchannel_send_action_tx_status( return; } - wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame"); - + wpa_printf(MSG_DEBUG, + "Off-channel: Delete matching pending action frame (dst=" + MACSTR " pending_action_tx=%p)", MAC2STR(dst), + wpa_s->pending_action_tx); + wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", + wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; @@ -250,8 +276,11 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, if (wpa_s->pending_action_tx) { wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action " - "frame TX to " MACSTR, - MAC2STR(wpa_s->pending_action_dst)); + "frame TX to " MACSTR " (pending_action_tx=%p)", + MAC2STR(wpa_s->pending_action_dst), + wpa_s->pending_action_tx); + wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", + wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); } wpa_s->pending_action_tx_done = 0; @@ -268,6 +297,12 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN); wpa_s->pending_action_freq = freq; wpa_s->pending_action_no_cck = no_cck; + wpa_printf(MSG_DEBUG, + "Off-channel: Stored pending action frame (dst=" MACSTR + " pending_action_tx=%p)", + MAC2STR(dst), wpa_s->pending_action_tx); + wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", + wpa_s->pending_action_tx); if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) { struct wpa_supplicant *iface; @@ -428,6 +463,9 @@ const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s) */ void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s) { + wpa_printf(MSG_DEBUG, + "Off-channel: Clear pending Action frame TX (pending_action_tx=%p", + wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 78bdd08..b1fdc28 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -53,6 +53,13 @@ */ #define P2P_GO_FREQ_CHANGE_TIME 5 +/** + * Defines CSA parameters which are used when GO evacuates the no longer valid + * channel (and if the driver supports channel switch). + */ +#define P2P_GO_CSA_COUNT 7 +#define P2P_GO_CSA_BLOCK_TX 0 + #ifndef P2P_MAX_CLIENT_IDLE /* * How many seconds to try to reconnect to the GO when connection in P2P client @@ -117,6 +124,10 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, int go); static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); +static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, + int *force_freq, int *pref_freq, int go, + unsigned int *pref_freq_list, + unsigned int *num_pref_freq); static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); @@ -340,6 +351,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, int social_channels_freq[] = { 2412, 2437, 2462, 60480 }; size_t ielen; u8 *n, i; + unsigned int bands; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -369,28 +381,6 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, if (wps_ie == NULL) goto fail; - ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); - ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); - if (ies == NULL) { - wpabuf_free(wps_ie); - goto fail; - } - wpabuf_put_buf(ies, wps_ie); - wpabuf_free(wps_ie); - - p2p_scan_ie(wpa_s->global->p2p, ies, dev_id); - - params->p2p_probe = 1; - n = os_malloc(wpabuf_len(ies)); - if (n == NULL) { - wpabuf_free(ies); - goto fail; - } - os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies)); - params->extra_ies = n; - params->extra_ies_len = wpabuf_len(ies); - wpabuf_free(ies); - switch (type) { case P2P_SCAN_SOCIAL: params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1, @@ -431,6 +421,29 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, break; } + ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); + ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); + if (ies == NULL) { + wpabuf_free(wps_ie); + goto fail; + } + wpabuf_put_buf(ies, wps_ie); + wpabuf_free(wps_ie); + + bands = wpas_get_bands(wpa_s, params->freqs); + p2p_scan_ie(wpa_s->global->p2p, ies, dev_id, bands); + + params->p2p_probe = 1; + n = os_malloc(wpabuf_len(ies)); + if (n == NULL) { + wpabuf_free(ies); + goto fail; + } + os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies)); + params->extra_ies = n; + params->extra_ies_len = wpabuf_len(ies); + wpabuf_free(ies); + radio_remove_works(wpa_s, "p2p-scan", 0); if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb, params) < 0) @@ -538,27 +551,39 @@ static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s) } +static unsigned int p2p_is_active_persistent_group(struct wpa_supplicant *wpa_s) +{ + return !wpa_s->p2p_mgmt && wpa_s->current_ssid && + !wpa_s->current_ssid->disabled && + wpa_s->current_ssid->p2p_group && + wpa_s->current_ssid->p2p_persistent_group; +} + + +static unsigned int p2p_is_active_persistent_go(struct wpa_supplicant *wpa_s) +{ + return p2p_is_active_persistent_group(wpa_s) && + wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO; +} + + /* Find an interface for a P2P group where we are the GO */ static struct wpa_supplicant * wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s) { struct wpa_supplicant *save = NULL; - struct wpa_ssid *s; if (!wpa_s) return NULL; for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { - for (s = wpa_s->conf->ssid; s; s = s->next) { - if (s->disabled || !s->p2p_group || - s->mode != WPAS_MODE_P2P_GO) - continue; + if (!p2p_is_active_persistent_go(wpa_s)) + continue; - /* Prefer a group with connected clients */ - if (p2p_get_group_num_members(wpa_s->p2p_group)) - return wpa_s; - save = wpa_s; - } + /* Prefer a group with connected clients */ + if (p2p_get_group_num_members(wpa_s->p2p_group)) + return wpa_s; + save = wpa_s; } /* No group with connected clients, so pick the one without (if any) */ @@ -566,29 +591,23 @@ wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s) } -/* Find an active P2P group where we are the GO */ -static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s, - u8 *bssid) +static unsigned int p2p_is_active_persistent_cli(struct wpa_supplicant *wpa_s) { - struct wpa_ssid *s, *empty = NULL; + return p2p_is_active_persistent_group(wpa_s) && + wpa_s->current_ssid->mode == WPAS_MODE_INFRA; +} - if (!wpa_s) - return 0; +/* Find an interface for a P2P group where we are the P2P Client */ +static struct wpa_supplicant * +wpas_p2p_get_cli_group(struct wpa_supplicant *wpa_s) +{ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { - for (s = wpa_s->conf->ssid; s; s = s->next) { - if (s->disabled || !s->p2p_group || - s->mode != WPAS_MODE_P2P_GO) - continue; - - os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN); - if (p2p_get_group_num_members(wpa_s->p2p_group)) - return s; - empty = s; - } + if (p2p_is_active_persistent_cli(wpa_s)) + return wpa_s; } - return empty; + return NULL; } @@ -607,20 +626,34 @@ wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s) } -static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) +static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, + unsigned int *force_freq, + unsigned int *pref_freq) { - struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s; + struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; u8 conncap = P2PS_SETUP_NONE; unsigned int owned_members = 0; - unsigned int owner = 0; - unsigned int client = 0; - struct wpa_supplicant *go_wpa_s; + struct wpa_supplicant *go_wpa_s, *cli_wpa_s; struct wpa_ssid *persistent_go; int p2p_no_group_iface; + unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role); + if (force_freq) + *force_freq = 0; + if (pref_freq) + *pref_freq = 0; + + size = P2P_MAX_PREF_CHANNELS; + if (force_freq && pref_freq && + !wpas_p2p_setup_freqs(wpa_s, 0, (int *) force_freq, + (int *) pref_freq, 0, pref_freq_list, &size)) + wpas_p2p_set_own_freq_preference(wpa_s, + *force_freq ? *force_freq : + *pref_freq); + /* * For non-concurrent capable devices: * If persistent_go, then no new. @@ -628,36 +661,21 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) * If client, then no GO. */ go_wpa_s = wpas_p2p_get_go_group(wpa_s); + if (go_wpa_s) + owned_members = p2p_get_group_num_members(go_wpa_s->p2p_group); persistent_go = wpas_p2p_get_persistent_go(wpa_s); p2p_no_group_iface = !wpas_p2p_create_iface(wpa_s); + cli_wpa_s = wpas_p2p_get_cli_group(wpa_s); - wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p", - go_wpa_s, persistent_go); - - for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s; - tmp_wpa_s = tmp_wpa_s->next) { - for (s = tmp_wpa_s->conf->ssid; s; s = s->next) { - wpa_printf(MSG_DEBUG, - "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d", - tmp_wpa_s, s, s->disabled, - s->p2p_group, s->mode); - if (!s->disabled && s->p2p_group) { - if (s->mode == WPAS_MODE_P2P_GO) { - owned_members += - p2p_get_group_num_members( - tmp_wpa_s->p2p_group); - owner++; - } else - client++; - } - } - } + wpa_printf(MSG_DEBUG, + "P2P: GO(iface)=%p members=%u CLI(iface)=%p persistent(ssid)=%p", + go_wpa_s, owned_members, cli_wpa_s, persistent_go); /* If not concurrent, restrict our choices */ if (p2p_no_group_iface) { wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface"); - if (client) + if (cli_wpa_s) return P2PS_SETUP_NONE; if (go_wpa_s) { @@ -689,10 +707,20 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) /* If a required role has been specified, handle it here */ if (role && role != P2PS_SETUP_NEW) { switch (incoming) { + case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW: + case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT: + /* + * Peer has an active GO, so if the role allows it and + * we do not have any active roles, become client. + */ + if ((role & P2PS_SETUP_CLIENT) && !go_wpa_s && + !cli_wpa_s) + return P2PS_SETUP_CLIENT; + + /* fall through */ + case P2PS_SETUP_NONE: case P2PS_SETUP_NEW: - case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT: - case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW: conncap = role; goto grp_owner; @@ -701,7 +729,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) * Must be a complimentary role - cannot be a client to * more than one peer. */ - if (incoming == role || client) + if (incoming == role || cli_wpa_s) return P2PS_SETUP_NONE; return P2PS_SETUP_CLIENT; @@ -727,7 +755,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) switch (incoming) { case P2PS_SETUP_NONE: case P2PS_SETUP_NEW: - if (client) + if (cli_wpa_s) conncap = P2PS_SETUP_GROUP_OWNER; else if (!owned_members) conncap = P2PS_SETUP_NEW; @@ -742,13 +770,13 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) break; case P2PS_SETUP_GROUP_OWNER: - if (!client) + if (!cli_wpa_s) conncap = P2PS_SETUP_CLIENT; break; case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW: case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT: - if (client) + if (cli_wpa_s) conncap = P2PS_SETUP_GROUP_OWNER; else { u8 r; @@ -770,15 +798,14 @@ grp_owner: (!incoming && (conncap & P2PS_SETUP_NEW))) { if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group)) conncap &= ~P2PS_SETUP_GROUP_OWNER; - wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d", - owner, owned_members, conncap); s = wpas_p2p_get_persistent_go(wpa_s); - - if (!s && !owner && p2p_no_group_iface) { + if (!s && !go_wpa_s && p2p_no_group_iface) { p2p_set_intended_addr(wpa_s->global->p2p, + wpa_s->p2p_mgmt ? + wpa_s->parent->own_addr : wpa_s->own_addr); - } else if (!s && !owner) { + } else if (!s && !go_wpa_s) { if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0) { wpa_printf(MSG_ERROR, @@ -850,7 +877,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, if (wpa_s->cross_connect_in_use) { wpa_s->cross_connect_in_use = 0; - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", wpa_s->ifname, wpa_s->cross_connect_uplink); } @@ -881,7 +908,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, break; } if (removal_reason != P2P_GROUP_REMOVAL_SILENT) { - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s", wpa_s->ifname, gtype, reason); } @@ -891,7 +918,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL) > 0) { + wpa_s->p2pdev, NULL) > 0) { wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation " "timeout"); wpa_s->p2p_in_provisioning = 0; @@ -926,6 +953,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, return 1; } + /* + * The primary interface was used for P2P group operations, so + * need to reset its p2pdev. + */ + wpa_s->p2pdev = wpa_s->parent; + if (!wpa_s->p2p_go_group_formation_completed) { wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; @@ -1043,7 +1076,7 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s, "go_dev_addr=" MACSTR, MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr)); - return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP; + return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP); } @@ -1101,7 +1134,8 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s, s->auth_alg = WPA_AUTH_ALG_OPEN; s->key_mgmt = WPA_KEY_MGMT_PSK; s->proto = WPA_PROTO_RSN; - s->pairwise_cipher = WPA_CIPHER_CCMP; + s->pbss = ssid->pbss; + s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP; s->export_keys = 1; if (ssid->passphrase) { os_free(s->passphrase); @@ -1241,7 +1275,7 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s, * Include PSK/passphrase only in the control interface message and * leave it out from the debug log entry. */ - wpa_msg_global_ctrl(wpa_s->parent, MSG_INFO, + wpa_msg_global_ctrl(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s %s ssid=\"%s\" freq=%d%s%s%s%s%s go_dev_addr=" MACSTR "%s%s", @@ -1267,7 +1301,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, int client; int persistent; u8 go_dev_addr[ETH_ALEN]; - int network_id = -1; /* * This callback is likely called for the main interface. Update wpa_s @@ -1284,7 +1317,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, wpa_s->group_formation_reported = 1; if (!success) { - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); wpas_notify_p2p_group_formation_failure(wpa_s, ""); if (already_deleted) @@ -1294,7 +1327,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, return; } - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS); ssid = wpa_s->current_ssid; @@ -1342,16 +1375,15 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, } if (persistent) - network_id = wpas_p2p_store_persistent_group(wpa_s->parent, - ssid, go_dev_addr); + wpas_p2p_store_persistent_group(wpa_s->p2pdev, + ssid, go_dev_addr); else { os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; } - if (network_id < 0 && ssid) - network_id = ssid->id; + if (!client) { - wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); + wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0); os_get_reltime(&wpa_s->global->p2p_go_wait_client); } } @@ -1368,6 +1400,25 @@ struct send_action_work { }; +static void wpas_p2p_free_send_action_work(struct wpa_supplicant *wpa_s) +{ + struct send_action_work *awork = wpa_s->p2p_send_action_work->ctx; + + wpa_printf(MSG_DEBUG, + "P2P: Free Action frame radio work @%p (freq=%u dst=" + MACSTR " src=" MACSTR " bssid=" MACSTR " wait_time=%u)", + wpa_s->p2p_send_action_work, awork->freq, + MAC2STR(awork->dst), MAC2STR(awork->src), + MAC2STR(awork->bssid), awork->wait_time); + wpa_hexdump(MSG_DEBUG, "P2P: Freeing pending Action frame", + awork->buf, awork->len); + os_free(awork); + wpa_s->p2p_send_action_work->ctx = NULL; + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; +} + + static void wpas_p2p_send_action_work_timeout(void *eloop_ctx, void *timeout_ctx) { @@ -1377,9 +1428,7 @@ static void wpas_p2p_send_action_work_timeout(void *eloop_ctx, return; wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out"); - os_free(wpa_s->p2p_send_action_work->ctx); - radio_work_done(wpa_s->p2p_send_action_work); - wpa_s->p2p_send_action_work = NULL; + wpas_p2p_free_send_action_work(wpa_s); } @@ -1387,11 +1436,13 @@ static void wpas_p2p_action_tx_clear(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_send_action_work) { struct send_action_work *awork; + awork = wpa_s->p2p_send_action_work->ctx; + wpa_printf(MSG_DEBUG, + "P2P: Clear Action TX work @%p (wait_time=%u)", + wpa_s->p2p_send_action_work, awork->wait_time); if (awork->wait_time == 0) { - os_free(awork); - radio_work_done(wpa_s->p2p_send_action_work); - wpa_s->p2p_send_action_work = NULL; + wpas_p2p_free_send_action_work(wpa_s); } else { /* * In theory, this should not be needed, but number of @@ -1447,7 +1498,7 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, wpa_s->pending_pd_before_join = 0; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req " "during p2p_connect-auto"); - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG "reason=no-ACK-to-PD-Req"); wpas_p2p_fallback_to_go_neg(wpa_s, 0); @@ -1590,11 +1641,11 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s, } else if (res->wps_method == WPS_NFC) { wpas_wps_start_nfc(wpa_s, res->peer_device_addr, res->peer_interface_addr, - wpa_s->parent->p2p_oob_dev_pw, - wpa_s->parent->p2p_oob_dev_pw_id, 1, - wpa_s->parent->p2p_oob_dev_pw_id == + wpa_s->p2pdev->p2p_oob_dev_pw, + wpa_s->p2pdev->p2p_oob_dev_pw_id, 1, + wpa_s->p2pdev->p2p_oob_dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER ? - wpa_s->parent->p2p_peer_oob_pubkey_hash : + wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL, NULL, 0, 0); #endif /* CONFIG_WPS_NFC */ @@ -1620,7 +1671,7 @@ static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s, if (!wpa_s->ap_iface) return; - persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid, + persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid, ssid->ssid_len); if (persistent == NULL) return; @@ -1685,8 +1736,8 @@ static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s, static void p2p_config_write(struct wpa_supplicant *wpa_s) { #ifndef CONFIG_NO_CONFIG_WRITE - if (wpa_s->parent->conf->update_config && - wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf)) + if (wpa_s->p2pdev->conf->update_config && + wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf)) wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); #endif /* CONFIG_NO_CONFIG_WRITE */ } @@ -1697,7 +1748,15 @@ static void p2p_go_configured(void *ctx, void *data) struct wpa_supplicant *wpa_s = ctx; struct p2p_go_neg_results *params = data; struct wpa_ssid *ssid; - int network_id = -1; + + wpa_s->ap_configured_cb = NULL; + wpa_s->ap_configured_cb_ctx = NULL; + wpa_s->ap_configured_cb_data = NULL; + if (!wpa_s->go_params) { + wpa_printf(MSG_ERROR, + "P2P: p2p_go_configured() called with wpa_s->go_params == NULL"); + return; + } p2p_go_save_group_common_freqs(wpa_s, params); p2p_go_dump_common_freqs(wpa_s); @@ -1715,8 +1774,8 @@ static void p2p_go_configured(void *ctx, void *data) params->persistent_group, ""); wpa_s->group_formation_reported = 1; - if (wpa_s->parent->p2ps_method_config_any) { - if (is_zero_ether_addr(wpa_s->parent->p2ps_join_addr)) { + if (wpa_s->p2pdev->p2ps_method_config_any) { + if (is_zero_ether_addr(wpa_s->p2pdev->p2ps_join_addr)) { wpa_dbg(wpa_s, MSG_DEBUG, "P2PS: Setting default PIN for ANY"); wpa_supplicant_ap_wps_pin(wpa_s, NULL, @@ -1725,24 +1784,24 @@ static void p2p_go_configured(void *ctx, void *data) } else { wpa_dbg(wpa_s, MSG_DEBUG, "P2PS: Setting default PIN for " MACSTR, - MAC2STR(wpa_s->parent->p2ps_join_addr)); + MAC2STR(wpa_s->p2pdev->p2ps_join_addr)); wpa_supplicant_ap_wps_pin( - wpa_s, wpa_s->parent->p2ps_join_addr, + wpa_s, wpa_s->p2pdev->p2ps_join_addr, "12345670", NULL, 0, 0); } - wpa_s->parent->p2ps_method_config_any = 0; + wpa_s->p2pdev->p2ps_method_config_any = 0; } os_get_reltime(&wpa_s->global->p2p_go_wait_client); if (params->persistent_group) { - network_id = wpas_p2p_store_persistent_group( - wpa_s->parent, ssid, + wpas_p2p_store_persistent_group( + wpa_s->p2pdev, ssid, wpa_s->global->p2p_dev_addr); wpas_p2p_add_psk_list(wpa_s, ssid); } - if (network_id < 0) - network_id = ssid->id; - wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); + + wpas_notify_p2p_group_started(wpa_s, ssid, + params->persistent_group, 0); wpas_p2p_cross_connect_setup(wpa_s); wpas_p2p_set_group_idle_timeout(wpa_s); @@ -1753,11 +1812,11 @@ static void p2p_go_configured(void *ctx, void *data) wpa_s->p2p_go_group_formation_completed = 0; wpa_s->global->p2p_group_formation = wpa_s; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); eloop_register_timeout( wpa_s->p2p_first_connection_timeout, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); } return; @@ -1775,17 +1834,17 @@ static void p2p_go_configured(void *ctx, void *data) params->peer_device_addr); #ifdef CONFIG_WPS_NFC } else if (params->wps_method == WPS_NFC) { - if (wpa_s->parent->p2p_oob_dev_pw_id != + if (wpa_s->p2pdev->p2p_oob_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && - !wpa_s->parent->p2p_oob_dev_pw) { + !wpa_s->p2pdev->p2p_oob_dev_pw) { wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known"); return; } wpas_ap_wps_add_nfc_pw( - wpa_s, wpa_s->parent->p2p_oob_dev_pw_id, - wpa_s->parent->p2p_oob_dev_pw, - wpa_s->parent->p2p_peer_oob_pk_hash_known ? - wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL); + wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id, + wpa_s->p2pdev->p2p_oob_dev_pw, + wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ? + wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL); #endif /* CONFIG_WPS_NFC */ } else if (wpa_s->p2p_pin[0]) wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr, @@ -1822,12 +1881,14 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, wpa_config_set_network_defaults(ssid); ssid->temporary = 1; ssid->p2p_group = 1; - ssid->p2p_persistent_group = params->persistent_group; + ssid->p2p_persistent_group = !!params->persistent_group; ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION : WPAS_MODE_P2P_GO; ssid->frequency = params->freq; ssid->ht40 = params->ht40; ssid->vht = params->vht; + ssid->max_oper_chwidth = params->max_oper_chwidth; + ssid->vht_center_freq2 = params->vht_center_freq2; ssid->ssid = os_zalloc(params->ssid_len + 1); if (ssid->ssid) { os_memcpy(ssid->ssid, params->ssid, params->ssid_len); @@ -1845,6 +1906,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, */ ssid->pairwise_cipher = WPA_CIPHER_GCMP; ssid->group_cipher = WPA_CIPHER_GCMP; + /* P2P GO in 60 GHz is always a PCP (PBSS) */ + ssid->pbss = 1; } if (os_strlen(params->passphrase) > 0) { ssid->passphrase = os_strdup(params->passphrase); @@ -1861,7 +1924,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk)); else if (ssid->passphrase) wpa_config_update_psk(ssid); - ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity; + ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity; wpa_s->ap_configured_cb = p2p_go_configured; wpa_s->ap_configured_cb_ctx = wpa_s; @@ -1885,7 +1948,12 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d = dst->conf; s = src->conf; -#define C(n) if (s->n) d->n = os_strdup(s->n) +#define C(n) \ +do { \ + if (s->n && !d->n) \ + d->n = os_strdup(s->n); \ +} while (0) + C(device_name); C(manufacturer); C(model_name); @@ -1913,7 +1981,10 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d->disable_scan_offload = s->disable_scan_offload; d->passive_scan = s->passive_scan; - if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) { + if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey && + !d->wps_nfc_pw_from_config) { + wpabuf_free(d->wps_nfc_dh_privkey); + wpabuf_free(d->wps_nfc_dh_pubkey); d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey); d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey); } @@ -2071,7 +2142,7 @@ static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s, int already_deleted) { eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); if (wpa_s->global->p2p) p2p_group_formation_failed(wpa_s->global->p2p); wpas_group_formation_completed(wpa_s, 0, already_deleted); @@ -2082,9 +2153,9 @@ static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure"); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); wpa_s->global->p2p_fail_on_wps_complete = 0; } @@ -2095,15 +2166,16 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) return; /* Speed up group formation timeout since this cannot succeed */ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); } static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *group_wpa_s; if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_drv_cancel_remain_on_channel(wpa_s); @@ -2129,6 +2201,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) res->ht40 = 1; if (wpa_s->p2p_go_vht) res->vht = 1; + res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth; + res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s " "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR @@ -2154,7 +2228,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) } if (wpa_s->create_p2p_iface) { - struct wpa_supplicant *group_wpa_s = + group_wpa_s = wpas_p2p_init_group_interface(wpa_s, res->role_go); if (group_wpa_s == NULL) { wpas_p2p_remove_pending_group_interface(wpa_s); @@ -2163,31 +2237,27 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) wpas_p2p_group_formation_failed(wpa_s, 1); return; } - if (group_wpa_s != wpa_s) { - os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin, - sizeof(group_wpa_s->p2p_pin)); - group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method; - } os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN); wpa_s->pending_interface_name[0] = '\0'; - group_wpa_s->p2p_in_provisioning = 1; - - if (res->role_go) { - wpas_start_wps_go(group_wpa_s, res, 1); - } else { - os_get_reltime(&group_wpa_s->scan_min_time); - wpas_start_wps_enrollee(group_wpa_s, res); - } } else { - wpa_s->p2p_in_provisioning = 1; - wpa_s->global->p2p_group_formation = wpa_s; + group_wpa_s = wpa_s->parent; + wpa_s->global->p2p_group_formation = group_wpa_s; + if (group_wpa_s != wpa_s) + wpas_p2p_clone_config(group_wpa_s, wpa_s); + } - if (res->role_go) { - wpas_start_wps_go(wpa_s, res, 1); - } else { - os_get_reltime(&wpa_s->scan_min_time); - wpas_start_wps_enrollee(ctx, res); - } + group_wpa_s->p2p_in_provisioning = 1; + group_wpa_s->p2pdev = wpa_s; + if (group_wpa_s != wpa_s) { + os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin, + sizeof(group_wpa_s->p2p_pin)); + group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method; + } + if (res->role_go) { + wpas_start_wps_go(group_wpa_s, res, 1); + } else { + os_get_reltime(&group_wpa_s->scan_min_time); + wpas_start_wps_enrollee(group_wpa_s, res); } wpa_s->p2p_long_listen = 0; @@ -2308,6 +2378,10 @@ static void wpas_dev_lost(void *ctx, const u8 *dev_addr) static void wpas_find_stopped(void *ctx) { struct wpa_supplicant *wpa_s = ctx; + + if (wpa_s->p2p_scan_work && wpas_abort_ongoing_scan(wpa_s) < 0) + wpa_printf(MSG_DEBUG, "P2P: Abort ongoing scan failed"); + wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED); wpas_notify_p2p_find_stopped(wpa_s); } @@ -2521,7 +2595,13 @@ static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, params[sizeof(params) - 1] = '\0'; if (config_methods & WPS_CONFIG_DISPLAY) { - generated_pin = wps_generate_pin(); + if (wps_generate_pin(&generated_pin) < 0) { + wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN"); + wpas_notify_p2p_provision_discovery( + wpa_s, peer, 0 /* response */, + P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0); + return; + } wpas_prov_disc_local_display(wpa_s, peer, params, generated_pin); } else if (config_methods & WPS_CONFIG_KEYPAD) @@ -2566,7 +2646,13 @@ static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) if (config_methods & WPS_CONFIG_DISPLAY) wpas_prov_disc_local_keypad(wpa_s, peer, params); else if (config_methods & WPS_CONFIG_KEYPAD) { - generated_pin = wps_generate_pin(); + if (wps_generate_pin(&generated_pin) < 0) { + wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN"); + wpas_notify_p2p_provision_discovery( + wpa_s, peer, 0 /* response */, + P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0); + return; + } wpas_prov_disc_local_display(wpa_s, peer, params, generated_pin); } else if (config_methods & WPS_CONFIG_PUSHBUTTON) @@ -2589,7 +2675,7 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer, if (wpa_s->p2p_fallback_to_go_neg) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto " "failed - fall back to GO Negotiation"); - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG "reason=PD-failed"); wpas_p2p_fallback_to_go_neg(wpa_s, 0); @@ -2685,6 +2771,29 @@ static int wpas_p2p_go_is_peer_freq(struct wpa_supplicant *wpa_s, int freq) } +static int wpas_sta_check_ecsa(struct hostapd_data *hapd, + struct sta_info *sta, void *ctx) +{ + int *ecsa_support = ctx; + + *ecsa_support &= sta->ecsa_supported; + + return 0; +} + + +/* Check if all the peers support eCSA */ +static int wpas_p2p_go_clients_support_ecsa(struct wpa_supplicant *wpa_s) +{ + int ecsa_support = 1; + + ap_for_each_sta(wpa_s->ap_iface->bss[0], wpas_sta_check_ecsa, + &ecsa_support); + + return ecsa_support; +} + + /** * Pick the best frequency to use from all the currently used frequencies. */ @@ -2811,7 +2920,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, "invitation"); return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } - os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN); + if (wpa_s->p2p_mgmt) + os_memcpy(group_bssid, wpa_s->parent->own_addr, + ETH_ALEN); + else + os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN); } else if (s->mode == WPAS_MODE_P2P_GO) { *go = 1; if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0) @@ -2893,12 +3006,31 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len)); if (s) { int go = s->mode == WPAS_MODE_P2P_GO; + if (go) { + wpa_msg_global(wpa_s, MSG_INFO, + P2P_EVENT_INVITATION_ACCEPTED + "sa=" MACSTR + " persistent=%d freq=%d", + MAC2STR(sa), s->id, op_freq); + } else { + wpa_msg_global(wpa_s, MSG_INFO, + P2P_EVENT_INVITATION_ACCEPTED + "sa=" MACSTR + " persistent=%d", + MAC2STR(sa), s->id); + } wpas_p2p_group_add_persistent( - wpa_s, s, go, 0, op_freq, 0, 0, NULL, + wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 1); } else if (bssid) { wpa_s->user_initiated_pd = 0; + wpa_msg_global(wpa_s, MSG_INFO, + P2P_EVENT_INVITATION_ACCEPTED + "sa=" MACSTR " go_dev_addr=" MACSTR + " bssid=" MACSTR " unknown-network", + MAC2STR(sa), MAC2STR(go_dev_addr), + MAC2STR(bssid)); wpas_p2p_join(wpa_s, bssid, go_dev_addr, wpa_s->p2p_wps_method, 0, op_freq, ssid, ssid_len); @@ -2999,7 +3131,7 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s, if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) return; /* Not operating as a GO in persistent group */ - ssid = wpas_p2p_get_persistent(wpa_s->parent, peer, + ssid = wpas_p2p_get_persistent(wpa_s->p2pdev, peer, ssid->ssid, ssid->ssid_len); wpas_remove_persistent_peer(wpa_s, ssid, peer, 1); } @@ -3027,9 +3159,37 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR, status, MAC2STR(peer)); if (wpa_s->pending_invite_ssid_id == -1) { + struct wpa_supplicant *group_if = + wpa_s->global->p2p_invite_group; + if (status == P2P_SC_FAIL_UNKNOWN_GROUP) wpas_remove_persistent_client(wpa_s, peer); - return; /* Invitation to active group */ + + /* + * Invitation to an active group. If this is successful and we + * are the GO, set the client wait to postpone some concurrent + * operations and to allow provisioning and connection to happen + * more quickly. + */ + if (status == P2P_SC_SUCCESS && + group_if && group_if->current_ssid && + group_if->current_ssid->mode == WPAS_MODE_P2P_GO) { + os_get_reltime(&wpa_s->global->p2p_go_wait_client); +#ifdef CONFIG_TESTING_OPTIONS + if (group_if->p2p_go_csa_on_inv) { + wpa_printf(MSG_DEBUG, + "Testing: force P2P GO CSA after invitation"); + eloop_cancel_timeout( + wpas_p2p_reconsider_moving_go, + wpa_s, NULL); + eloop_register_timeout( + 0, 50000, + wpas_p2p_reconsider_moving_go, + wpa_s, NULL); + } +#endif /* CONFIG_TESTING_OPTIONS */ + } + return; } if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { @@ -3083,7 +3243,9 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, ssid->mode == WPAS_MODE_P2P_GO, wpa_s->p2p_persistent_go_freq, freq, + wpa_s->p2p_go_vht_center_freq2, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht, + wpa_s->p2p_go_max_oper_chwidth, channels, ssid->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : @@ -3169,21 +3331,6 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s, } -static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, - u16 num_modes, - enum hostapd_hw_mode mode) -{ - u16 i; - - for (i = 0; i < num_modes; i++) { - if (modes[i].mode == mode) - return &modes[i]; - } - - return NULL; -} - - enum chan_allowed { NOT_ALLOWED, NO_IR, ALLOWED }; @@ -3217,49 +3364,12 @@ static int has_channel(struct wpa_global *global, } -struct p2p_oper_class_map { - enum hostapd_hw_mode mode; - u8 op_class; - u8 min_chan; - u8 max_chan; - u8 inc; - enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw; -}; - -static const struct p2p_oper_class_map op_class[] = { - { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 }, -#if 0 /* Do not enable HT40 on 2 GHz for now */ - { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS }, - { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS }, -#endif - { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 }, - { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 }, - { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 }, - { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS }, - { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS }, - { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS }, - { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS }, - - /* - * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center - * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of - * 80 MHz, but currently use the following definition for simplicity - * (these center frequencies are not actual channels, which makes - * has_channel() fail). wpas_p2p_verify_80mhz() should take care of - * removing invalid channels. - */ - { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 }, - { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160 }, - { -1, 0, 0, 0, 0, BW20 } -}; - - static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel) { u8 center_channels[] = { 42, 58, 106, 122, 138, 155 }; - unsigned int i; + size_t i; if (mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; @@ -3315,6 +3425,75 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, } +static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s, + 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 wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + u8 channel, u8 bw) +{ + u8 center_chan; + int i, flags; + enum chan_allowed res, ret = ALLOWED; + + center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel); + if (!center_chan) + return NOT_ALLOWED; + /* VHT 160 MHz uses DFS channels in most countries. */ + + /* Check all the channels are available */ + for (i = 0; i < 8; i++) { + int adj_chan = center_chan - 14 + i * 4; + + res = has_channel(wpa_s->global, mode, adj_chan, &flags); + if (res == NOT_ALLOWED) + return NOT_ALLOWED; + + if (res == NO_IR) + ret = NO_IR; + + if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) + return NOT_ALLOWED; + if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) + return NOT_ALLOWED; + if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) + return NOT_ALLOWED; + if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) + return NOT_ALLOWED; + if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) + return NOT_ALLOWED; + if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) + return NOT_ALLOWED; + if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) + return NOT_ALLOWED; + if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)) + return NOT_ALLOWED; + } + + return ret; +} + + static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel, u8 bw) @@ -3333,6 +3512,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, res2 = has_channel(wpa_s->global, mode, channel + 4, NULL); } else if (bw == BW80) { res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw); + } else if (bw == BW160) { + res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw); } if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) @@ -3359,11 +3540,14 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, cla = cli_cla = 0; - for (op = 0; op_class[op].op_class; op++) { - const struct p2p_oper_class_map *o = &op_class[op]; + for (op = 0; global_op_class[op].op_class; op++) { + const struct oper_class_map *o = &global_op_class[op]; u8 ch; struct p2p_reg_class *reg = NULL, *cli_reg = NULL; + if (o->p2p == NO_P2P_SUPP) + continue; + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode); if (mode == NULL) continue; @@ -3418,10 +3602,13 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, int op; enum chan_allowed ret; - for (op = 0; op_class[op].op_class; op++) { - const struct p2p_oper_class_map *o = &op_class[op]; + for (op = 0; global_op_class[op].op_class; op++) { + const struct oper_class_map *o = &global_op_class[op]; u8 ch; + if (o->p2p == NO_P2P_SUPP) + continue; + for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { if (o->mode != HOSTAPD_MODE_IEEE80211A || (o->bw != BW40PLUS && o->bw != BW40MINUS) || @@ -3446,6 +3633,15 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, } +int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel) +{ + if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160)) + return 0; + return wpas_p2p_get_center_160mhz(wpa_s, mode, channel); +} + + static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf, size_t buf_len) { @@ -3577,6 +3773,7 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s, return -1; } + p2pdev_wpa_s->p2pdev = p2pdev_wpa_s; wpa_s->pending_interface_name[0] = '\0'; return 0; } @@ -3638,11 +3835,12 @@ static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid, static int wpas_get_go_info(void *ctx, u8 *intended_addr, - u8 *ssid, size_t *ssid_len, int *group_iface) + u8 *ssid, size_t *ssid_len, int *group_iface, + unsigned int *freq) { struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *go; struct wpa_ssid *s; - u8 bssid[ETH_ALEN]; /* * group_iface will be set to 1 only if a dedicated interface for P2P @@ -3652,17 +3850,25 @@ static int wpas_get_go_info(void *ctx, u8 *intended_addr, * that the pending interface should be used. */ *group_iface = 0; - s = wpas_p2p_group_go_ssid(wpa_s, bssid); - if (!s) { + + if (freq) + *freq = 0; + + go = wpas_p2p_get_go_group(wpa_s); + if (!go) { s = wpas_p2p_get_persistent_go(wpa_s); *group_iface = wpas_p2p_create_iface(wpa_s); if (s) - os_memcpy(bssid, s->bssid, ETH_ALEN); + os_memcpy(intended_addr, s->bssid, ETH_ALEN); else return 0; + } else { + s = go->current_ssid; + os_memcpy(intended_addr, go->own_addr, ETH_ALEN); + if (freq) + *freq = go->assoc_freq; } - os_memcpy(intended_addr, bssid, ETH_ALEN); os_memcpy(ssid, s->ssid, s->ssid_len); *ssid_len = s->ssid_len; @@ -3750,11 +3956,13 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, const u8 *persist_ssid, size_t persist_ssid_size, int response_done, int prov_start, const char *session_info, - const u8 *feat_cap, size_t feat_cap_len) + const u8 *feat_cap, size_t feat_cap_len, + unsigned int freq, + const u8 *group_ssid, size_t group_ssid_len) { struct wpa_supplicant *wpa_s = ctx; u8 mac[ETH_ALEN]; - struct wpa_ssid *persistent_go, *stale, *s; + struct wpa_ssid *persistent_go, *stale, *s = NULL; int save_config = 0; struct wpa_supplicant *go_wpa_s; char feat_cap_str[256]; @@ -3825,8 +4033,9 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, } /* Clean up stale persistent groups with this device */ - s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid, - persist_ssid_size); + if (persist_ssid && persist_ssid_size) + s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid, + persist_ssid_size); if (persist_ssid && s && s->mode != WPAS_MODE_P2P_GO && is_zero_ether_addr(grp_mac)) { @@ -3908,6 +4117,7 @@ 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 (!wpas_p2p_create_iface(wpa_s)) os_memcpy(go_ifname, wpa_s->ifname, @@ -3922,7 +4132,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP, dev, adv_mac, ses_mac, grp_mac, adv_id, ses_id, 0, 0, - NULL, 0, 0, 0, NULL, NULL, 0); + NULL, 0, 0, 0, NULL, NULL, 0, 0, + NULL, 0); return; } @@ -3930,13 +4141,13 @@ 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, 0, 0, 0, NULL, + 0, 0, freq, 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, 0, 0, 0); + wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0); } if (passwd_id == DEV_PW_P2PS_DEFAULT) { @@ -3989,16 +4200,24 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, } if (conncap == P2PS_SETUP_CLIENT) { + char ssid_hex[32 * 2 + 1]; + + if (group_ssid) + wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex), + group_ssid, group_ssid_len); + else + ssid_hex[0] = '\0'; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_P2PS_PROVISION_DONE MACSTR " status=%d conncap=%x" " adv_id=%x adv_mac=" MACSTR " session=%x mac=" MACSTR - " dev_passwd_id=%d join=" MACSTR "%s", + " dev_passwd_id=%d join=" MACSTR "%s%s%s", MAC2STR(dev), status, conncap, adv_id, MAC2STR(adv_mac), ses_id, MAC2STR(ses_mac), - passwd_id, MAC2STR(grp_mac), feat_cap_str); + passwd_id, MAC2STR(grp_mac), feat_cap_str, + group_ssid ? " group_ssid=" : "", ssid_hex); } else { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_P2PS_PROVISION_DONE MACSTR @@ -4025,10 +4244,13 @@ static int wpas_prov_disc_resp_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *persistent_go; + unsigned int freq; if (!wpa_s->global->pending_p2ps_group) return 0; + freq = wpa_s->global->pending_p2ps_group_freq; + wpa_s->global->pending_p2ps_group_freq = 0; wpa_s->global->pending_p2ps_group = 0; if (wpas_p2p_get_go_group(wpa_s)) @@ -4037,11 +4259,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, NULL, + wpa_s, persistent_go, 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, 0, 0, 0); + wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0); } return 1; @@ -4333,8 +4555,7 @@ static void wpas_p2p_deinit_global(struct wpa_global *global) static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s) { - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && - wpa_s->conf->p2p_no_group_iface) + if (wpa_s->conf->p2p_no_group_iface) return 0; /* separate interface disabled per configuration */ if (wpa_s->drv_flags & (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE | @@ -4415,7 +4636,7 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s) MAC2STR(wpa_s->pending_join_dev_addr)); return; } - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); wpas_notify_p2p_group_formation_failure(wpa_s, ""); } @@ -4551,7 +4772,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, if (join < 0) { wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " "running a GO -> use GO Negotiation"); - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG "reason=peer-not-running-GO"); wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, @@ -4559,10 +4780,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_persistent_group, 0, 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, + wpa_s->p2p_go_vht_center_freq2, wpa_s->p2p_persistent_id, wpa_s->p2p_pd_before_go_neg, wpa_s->p2p_go_ht40, - wpa_s->p2p_go_vht); + wpa_s->p2p_go_vht, + wpa_s->p2p_go_max_oper_chwidth, + NULL, 0); return; } @@ -4570,7 +4794,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, "try to join the group", join ? "" : " in older scan"); if (!join) { - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED); wpa_s->p2p_fallback_to_go_neg = 1; } @@ -4608,8 +4832,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr, wpa_s->p2p_join_ssid, wpa_s->p2p_join_ssid_len); - } - if (!bss) { + } else if (!bss) { wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID " MACSTR, MAC2STR(wpa_s->pending_join_iface_addr)); bss = wpa_bss_get_bssid_latest(wpa_s, @@ -4640,7 +4863,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, u16 method; if (wpas_check_freq_conflict(wpa_s, freq) > 0) { - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE "reason=FREQ_CONFLICT"); wpas_notify_p2p_group_formation_failure( @@ -4708,7 +4931,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, start: /* Start join operation immediately */ - wpas_p2p_join_start(wpa_s, 0, NULL, 0); + wpas_p2p_join_start(wpa_s, 0, wpa_s->p2p_join_ssid, + wpa_s->p2p_join_ssid_len); } @@ -4720,6 +4944,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, struct wpabuf *wps_ie, *ies; size_t ielen; int freqs[2] = { 0, 0 }; + unsigned int bands; os_memset(¶ms, 0, sizeof(params)); @@ -4745,22 +4970,6 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, return; } - ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); - ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); - if (ies == NULL) { - wpabuf_free(wps_ie); - wpas_p2p_scan_res_join(wpa_s, NULL); - return; - } - wpabuf_put_buf(ies, wps_ie); - wpabuf_free(wps_ie); - - p2p_scan_ie(wpa_s->global->p2p, ies, NULL); - - params.p2p_probe = 1; - params.extra_ies = wpabuf_head(ies); - params.extra_ies_len = wpabuf_len(ies); - if (!freq) { int oper_freq; /* @@ -4777,6 +4986,23 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, params.freqs = freqs; } + ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); + ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); + if (ies == NULL) { + wpabuf_free(wps_ie); + wpas_p2p_scan_res_join(wpa_s, NULL); + return; + } + wpabuf_put_buf(ies, wps_ie); + wpabuf_free(wps_ie); + + bands = wpas_get_bands(wpa_s, freqs); + p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands); + + params.p2p_probe = 1; + params.extra_ies = wpabuf_head(ies); + params.extra_ies_len = wpabuf_len(ies); + /* * Run a scan to update BSS table and start Provision Discovery once * the new scan results become available. @@ -4874,8 +5100,13 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, res.ssid_len = ssid_len; os_memcpy(res.ssid, ssid, ssid_len); } else { - bss = wpa_bss_get_bssid_latest(wpa_s, - wpa_s->pending_join_iface_addr); + if (ssid && ssid_len) { + bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr, + ssid, ssid_len); + } else { + bss = wpa_bss_get_bssid_latest( + wpa_s, wpa_s->pending_join_iface_addr); + } if (bss) { res.freq = bss->freq; res.ssid_len = bss->ssid_len; @@ -4883,6 +5114,11 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)", bss->freq, wpa_ssid_txt(bss->ssid, bss->ssid_len)); + } else if (ssid && ssid_len) { + res.ssid_len = ssid_len; + os_memcpy(res.ssid, ssid, ssid_len); + wpa_printf(MSG_DEBUG, "P2P: Join target GO (SSID %s)", + wpa_ssid_txt(ssid, ssid_len)); } } @@ -5067,12 +5303,17 @@ exit_free: * initiating Group Owner negotiation * @go_intent: GO Intent or -1 to use default * @freq: Frequency for the group or 0 for auto-selection + * @freq2: Center frequency of segment 1 for the GO operating in VHT 80P80 mode * @persistent_id: Persistent group credentials to use for forcing GO * parameters or -1 to generate new values (SSID/passphrase) * @pd: Whether to send Provision Discovery prior to GO Negotiation as an * interoperability workaround when initiating group formation * @ht40: Start GO with 40 MHz channel width * @vht: Start GO with VHT support + * @vht_chwidth: Channel width supported by GO operating with VHT support + * (VHT_CHANWIDTH_*). + * @group_ssid: Specific Group SSID for join or %NULL if not set + * @group_ssid_len: Length of @group_ssid in octets * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported @@ -5080,8 +5321,10 @@ exit_free: int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, int persistent_group, int auto_join, int join, int auth, - int go_intent, int freq, int persistent_id, int pd, - int ht40, int vht) + 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, + size_t group_ssid_len) { int force_freq = 0, pref_freq = 0; int ret = 0, res; @@ -5105,6 +5348,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->global->p2p_fail_on_wps_complete = 0; wpa_s->global->pending_p2ps_group = 0; + wpa_s->global->pending_p2ps_group_freq = 0; wpa_s->p2ps_method_config_any = 0; if (go_intent < 0) @@ -5122,17 +5366,23 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_pd_before_go_neg = !!pd; wpa_s->p2p_go_ht40 = !!ht40; 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; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); else if (wps_method == WPS_PIN_DISPLAY) { - ret = wps_generate_pin(); + if (wps_generate_pin((unsigned int *) &ret) < 0) + return -1; res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d", ret); if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res)) wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0'; wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s", wpa_s->p2p_pin); + } else if (wps_method == WPS_P2PS) { + /* Force the P2Ps default PIN to be used */ + os_strlcpy(wpa_s->p2p_pin, "12345670", sizeof(wpa_s->p2p_pin)); } else wpa_s->p2p_pin[0] = '\0'; @@ -5161,7 +5411,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } wpa_s->user_initiated_pd = 1; if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method, - auto_join, freq, NULL, 0) < 0) + auto_join, freq, + group_ssid, group_ssid_len) < 0) return -1; return ret; } @@ -5191,7 +5442,10 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if_addr = wpa_s->pending_interface_addr; } else { - if_addr = wpa_s->own_addr; + if (wpa_s->p2p_mgmt) + if_addr = wpa_s->parent->own_addr; + else + if_addr = wpa_s->own_addr; os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN); } @@ -5520,29 +5774,51 @@ out: static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params, - int freq, int ht40, int vht, + int freq, int vht_center_freq2, int ht40, + int vht, int max_oper_chwidth, const struct p2p_channels *channels) { struct wpa_used_freq_data *freqs; unsigned int cand; unsigned int num, i; + int ignore_no_freqs = 0; + int unused_channels = wpas_p2p_num_unused_channels(wpa_s) > 0; os_memset(params, 0, sizeof(*params)); params->role_go = 1; params->ht40 = ht40; params->vht = vht; - - if (wpa_s->p2p_group_common_freqs_num) - wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO", - __func__); + params->max_oper_chwidth = max_oper_chwidth; + params->vht_center_freq2 = vht_center_freq2; freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(struct wpa_used_freq_data)); if (!freqs) return -1; - num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, - wpa_s->num_multichan_concurrent); + num = get_shared_radio_freqs_data(wpa_s, freqs, + wpa_s->num_multichan_concurrent); + + if (wpa_s->current_ssid && + wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO && + wpa_s->wpa_state == WPA_COMPLETED) { + wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO", + __func__); + + /* + * If the frequency selection is done for an active P2P GO that + * is not sharing a frequency, allow to select a new frequency + * even if there are no unused frequencies as we are about to + * move the P2P GO so its frequency can be re-used. + */ + for (i = 0; i < num; i++) { + if (freqs[i].freq == wpa_s->current_ssid->frequency && + freqs[i].flags == 0) { + ignore_no_freqs = 1; + break; + } + } + } /* try using the forced freq */ if (freq) { @@ -5563,7 +5839,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, } } - if (wpas_p2p_num_unused_channels(wpa_s) <= 0) { + if (!ignore_no_freqs && !unused_channels) { wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%d MHz) as all the channels are in use", freq); @@ -5578,12 +5854,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, } /* consider using one of the shared frequencies */ - if (num) { + if (num && + (!wpa_s->conf->p2p_ignore_shared_freq || !unused_channels)) { cand = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num); if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { wpa_printf(MSG_DEBUG, "P2P: Use shared freq (%d MHz) for GO", - freq); + cand); params->freq = cand; goto success; } @@ -5594,14 +5871,14 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, freqs[i].freq)) { wpa_printf(MSG_DEBUG, "P2P: Use shared freq (%d MHz) for GO", - freq); + freqs[i].freq); params->freq = freqs[i].freq; goto success; } } } - if (wpas_p2p_num_unused_channels(wpa_s) <= 0) { + if (!ignore_no_freqs && !unused_channels) { wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using"); goto fail; @@ -5714,9 +5991,20 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, struct wpa_supplicant *group_wpa_s; if (!wpas_p2p_create_iface(wpa_s)) { - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group " - "operations"); + if (wpa_s->p2p_mgmt) { + /* + * We may be called on the p2p_dev interface which + * cannot be used for group operations, so always use + * the primary interface. + */ + wpa_s->parent->p2pdev = wpa_s; + wpa_s = wpa_s->parent; + } + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Use primary interface for group operations"); wpa_s->p2p_first_connection_timeout = 0; + if (wpa_s != wpa_s->p2pdev) + wpas_p2p_clone_config(wpa_s, wpa_s->p2pdev); return wpa_s; } @@ -5746,15 +6034,18 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * @persistent_group: Whether to create a persistent group * @freq: Frequency for the group or 0 to indicate no hardcoding + * @vht_center_freq2: segment_1 center frequency for GO operating in VHT 80P80 * @ht40: Start GO with 40 MHz channel width * @vht: Start GO with VHT support + * @vht_chwidth: channel bandwidth for GO operating with VHT support * Returns: 0 on success, -1 on failure * * This function creates a new P2P group with the local end as the Group Owner, * i.e., without using Group Owner Negotiation. */ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, - int freq, int ht40, int vht) + int freq, int vht_center_freq2, int ht40, int vht, + int max_oper_chwidth) { struct p2p_go_neg_results params; @@ -5772,7 +6063,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, if (freq < 0) return -1; - if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, vht, NULL)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2, + ht40, vht, max_oper_chwidth, NULL)) return -1; if (params.freq && !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) { @@ -5826,8 +6118,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, wpa_config_set_network_defaults(ssid); ssid->temporary = 1; ssid->proto = WPA_PROTO_RSN; - ssid->pairwise_cipher = WPA_CIPHER_CCMP; - ssid->group_cipher = WPA_CIPHER_CCMP; + ssid->pbss = params->pbss; + ssid->pairwise_cipher = params->pbss ? WPA_CIPHER_GCMP : + WPA_CIPHER_CCMP; + ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP; ssid->key_mgmt = WPA_KEY_MGMT_PSK; ssid->ssid = os_malloc(params->ssid_len); if (ssid->ssid == NULL) { @@ -5848,12 +6142,14 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, wpa_s->show_group_started = 1; wpa_s->p2p_in_invitation = 1; wpa_s->p2p_invite_go_freq = freq; + wpa_s->p2p_go_group_formation_completed = 0; + wpa_s->global->p2p_group_formation = wpa_s; - eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev, NULL); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); wpa_supplicant_select_network(wpa_s, ssid); return 0; @@ -5862,8 +6158,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, 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 ht40, - int vht, const struct p2p_channels *channels, + int force_freq, int neg_freq, + int vht_center_freq2, int ht40, + int vht, int max_oper_chwidth, + const struct p2p_channels *channels, int connection_timeout, int force_scan) { struct p2p_go_neg_results params; @@ -5878,7 +6176,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, "already running"); if (go == 0 && eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL)) { + wpa_s->p2pdev, NULL)) { /* * This can happen if Invitation Response frame was lost * and the peer (GO of a persistent group) tries to @@ -5891,7 +6189,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, "P2P: Reschedule group formation timeout since peer is still trying to invite us"); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); } return 0; } @@ -5937,7 +6235,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, return -1; } - if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, vht, channels)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2, + ht40, vht, max_oper_chwidth, channels)) return -1; params.role_go = 1; @@ -6019,7 +6318,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct p2p_group *group; struct p2p_group_config *cfg; - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || + !ssid->p2p_group) return NULL; cfg = os_zalloc(sizeof(*cfg)); @@ -6042,6 +6342,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, cfg->cb_ctx = wpa_s; cfg->ie_update = wpas_p2p_ie_update; cfg->idle_update = wpas_p2p_idle_update; + cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start) + != 0; group = p2p_group_init(wpa_s->global->p2p, cfg); if (group == NULL) @@ -6073,7 +6375,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr); } - eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev, NULL); wpa_s->p2p_go_group_formation_completed = 1; if (ssid && ssid->mode == WPAS_MODE_INFRA) { @@ -6088,7 +6390,9 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, P2P_MAX_INITIAL_CONN_WAIT); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); + /* Complete group formation on successful data connection. */ + wpa_s->p2p_go_group_formation_completed = 0; } else if (ssid) { /* * Use a separate timeout for initial data connection to @@ -6100,7 +6404,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, P2P_MAX_INITIAL_CONN_WAIT_GO); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); /* * Complete group formation on first successful data connection */ @@ -6139,7 +6443,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, wpa_s->global->p2p_fail_on_wps_complete = 1; eloop_deplete_timeout(0, 50000, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); } } @@ -6164,11 +6468,14 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, u16 config_methods; wpa_s->global->pending_p2ps_group = 0; + wpa_s->global->pending_p2ps_group_freq = 0; wpa_s->p2p_fallback_to_go_neg = 0; wpa_s->pending_pd_use = NORMAL_PD; if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) { p2ps_prov->conncap = p2ps_group_capability( - wpa_s, P2PS_SETUP_NONE, p2ps_prov->role); + wpa_s, P2PS_SETUP_NONE, p2ps_prov->role, + &p2ps_prov->force_freq, &p2ps_prov->pref_freq); + wpa_printf(MSG_DEBUG, "P2P: %s conncap: %d - ASP parsed: %x %x %d %s", __func__, p2ps_prov->conncap, @@ -6229,7 +6536,12 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s) if (!offchannel_pending_action_tx(wpa_s)) return; - wpas_p2p_action_tx_clear(wpa_s); + if (wpa_s->p2p_send_action_work) { + wpas_p2p_free_send_action_work(wpa_s); + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + offchannel_send_action_done(wpa_s); + } wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new " "operation request"); @@ -6320,6 +6632,12 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout) if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + if (wpa_s->p2p_lo_started) { + wpa_printf(MSG_DEBUG, + "P2P: Cannot start P2P listen, it is offloaded"); + return -1; + } + wpa_supplicant_cancel_sched_scan(wpa_s); wpas_p2p_clear_pending_action_tx(wpa_s); @@ -6393,7 +6711,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr, return 0; switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid, - ie, ie_len, rx_freq)) { + ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) { case P2P_PREQ_NOT_P2P: wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal); @@ -6425,12 +6743,15 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies) { + unsigned int bands; + if (wpa_s->global->p2p_disabled) return; if (wpa_s->global->p2p == NULL) return; - p2p_scan_ie(wpa_s->global->p2p, ies, NULL); + bands = wpas_get_bands(wpa_s, NULL); + p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands); } @@ -6460,7 +6781,8 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) /* Invite to reinvoke a persistent group */ 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 ht40, int vht, int pref_freq) + int vht_center_freq2, int ht40, int vht, int max_chwidth, + int pref_freq) { enum p2p_invite_role role; u8 *bssid = NULL; @@ -6477,6 +6799,9 @@ 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_max_oper_chwidth = max_chwidth; + wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2; if (ssid->mode == WPAS_MODE_P2P_GO) { role = P2P_INVITE_ROLE_GO; if (peer_addr == NULL) { @@ -6493,7 +6818,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return -1; } bssid = wpa_s->pending_interface_addr; - } else + } else if (wpa_s->p2p_mgmt) + bssid = wpa_s->parent->own_addr; + else bssid = wpa_s->own_addr; } else { role = P2P_INVITE_ROLE_CLIENT; @@ -6507,11 +6834,12 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, pref_freq_list, &size); if (res) return res; - p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size); + if (wpa_s->parent->conf->p2p_ignore_shared_freq && no_pref_freq_given && pref_freq > 0 && wpa_s->num_multichan_concurrent > 1 && @@ -6549,6 +6877,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, wpa_s->p2p_persistent_go_freq = 0; wpa_s->p2p_go_ht40 = 0; wpa_s->p2p_go_vht = 0; + wpa_s->p2p_go_vht_center_freq2 = 0; + wpa_s->p2p_go_max_oper_chwidth = 0; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_strcmp(wpa_s->ifname, ifname) == 0) @@ -6568,7 +6898,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, wpa_s->global->p2p_invite_group = wpa_s; persistent = ssid->p2p_persistent_group && - wpas_p2p_get_persistent(wpa_s->parent, peer_addr, + wpas_p2p_get_persistent(wpa_s->p2pdev, peer_addr, ssid->ssid, ssid->ssid_len); if (ssid->mode == WPAS_MODE_P2P_GO) { @@ -6591,7 +6921,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, freq = wpa_s->current_bss ? wpa_s->current_bss->freq : (int) wpa_s->assoc_freq; } - wpa_s->parent->pending_invite_ssid_id = -1; + wpa_s->p2pdev->pending_invite_ssid_id = -1; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -6614,7 +6944,6 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; u8 go_dev_addr[ETH_ALEN]; - int network_id = -1; int persistent; int freq; u8 ip[3 * 4]; @@ -6622,13 +6951,22 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) { eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); } if (!wpa_s->show_group_started || !ssid) return; wpa_s->show_group_started = 0; + if (!wpa_s->p2p_go_group_formation_completed && + wpa_s->global->p2p_group_formation == wpa_s) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Marking group formation completed on client on data connection"); + wpa_s->p2p_go_group_formation_completed = 1; + wpa_s->global->p2p_group_formation = NULL; + wpa_s->p2p_in_provisioning = 0; + wpa_s->p2p_in_invitation = 0; + } os_memset(go_dev_addr, 0, ETH_ALEN); if (ssid->bssid_set) @@ -6664,11 +7002,10 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) ip_addr); if (persistent) - network_id = wpas_p2p_store_persistent_group(wpa_s->parent, - ssid, go_dev_addr); - if (network_id < 0) - network_id = ssid->id; - wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1); + wpas_p2p_store_persistent_group(wpa_s->p2pdev, + ssid, go_dev_addr); + + wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1); } @@ -7001,7 +7338,7 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled) iface->cross_connect_enabled = 0; iface->cross_connect_in_use = 0; - wpa_msg_global(iface->parent, MSG_INFO, + wpa_msg_global(iface->p2pdev, MSG_INFO, P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", iface->ifname, iface->cross_connect_uplink); @@ -7031,7 +7368,7 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink) continue; iface->cross_connect_in_use = 1; - wpa_msg_global(iface->parent, MSG_INFO, + wpa_msg_global(iface->p2pdev, MSG_INFO, P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", iface->ifname, iface->cross_connect_uplink); } @@ -7051,7 +7388,7 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink) if (!iface->cross_connect_in_use) continue; - wpa_msg_global(iface->parent, MSG_INFO, + wpa_msg_global(iface->p2pdev, MSG_INFO, P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", iface->ifname, iface->cross_connect_uplink); iface->cross_connect_in_use = 0; @@ -7114,7 +7451,7 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s) break; wpa_s->cross_connect_in_use = 1; - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", wpa_s->ifname, wpa_s->cross_connect_uplink); break; @@ -7130,8 +7467,8 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC " "session overlap"); - if (wpa_s != wpa_s->parent) - wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP); + if (wpa_s != wpa_s->p2pdev) + wpa_msg_ctrl(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_OVERLAP); wpas_p2p_group_formation_failed(wpa_s, 0); return 1; } @@ -7238,7 +7575,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) wpa_s->ifname); found = 1; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); if (wpa_s->p2p_in_provisioning) { wpas_group_formation_completed(wpa_s, 0, 0); break; @@ -7251,6 +7588,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) wpa_s->ifname); found = 1; wpas_p2p_group_formation_failed(wpa_s, 0); + break; } } @@ -7367,7 +7705,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, { if (wpa_s->p2p_in_provisioning && ssid->p2p_group && eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL) > 0) { + wpa_s->p2pdev, NULL) > 0) { /** * Remove the network by scheduling the group formation * timeout to happen immediately. The teardown code @@ -7379,7 +7717,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to " "P2P group network getting removed"); eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); + wpa_s->p2pdev, NULL); } } @@ -7423,7 +7761,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *addr) { if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL) > 0) { + wpa_s->p2pdev, NULL) > 0) { /* * This can happen if WPS provisioning step is not terminated * cleanly (e.g., P2P Client does not send WSC_Done). Since the @@ -7479,10 +7817,12 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, + wpa_s->p2p_go_vht_center_freq2, wpa_s->p2p_persistent_id, wpa_s->p2p_pd_before_go_neg, wpa_s->p2p_go_ht40, - wpa_s->p2p_go_vht); + wpa_s->p2p_go_vht, + wpa_s->p2p_go_max_oper_chwidth, NULL, 0); return ret; } @@ -7500,7 +7840,7 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - " "fallback to GO Negotiation"); - wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG "reason=GO-not-found"); res = wpas_p2p_fallback_to_go_neg(wpa_s, 1); @@ -7609,7 +7949,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, return; } - persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid, + persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid, ssid->ssid_len); if (!persistent) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not find persistent group information to store the new PSK"); @@ -7638,7 +7978,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, os_free(last); } - wpas_p2p_remove_psk_entry(wpa_s->parent, persistent, + wpas_p2p_remove_psk_entry(wpa_s->p2pdev, persistent, p2p_dev_addr ? p2p_dev_addr : mac_addr, p2p_dev_addr == NULL); if (p2p_dev_addr) { @@ -7650,8 +7990,8 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, } dl_list_add(&persistent->psk_list, &p->list); - if (wpa_s->parent->conf->update_config && - wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf)) + if (wpa_s->p2pdev->conf->update_config && + wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf)) wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); } @@ -7830,14 +8170,14 @@ int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Two 4-way handshake failures for a P2P group - go_dev_addr=" MACSTR, MAC2STR(go_dev_addr)); - persistent = wpas_p2p_get_persistent(wpa_s->parent, go_dev_addr, + persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, go_dev_addr, ssid->ssid, ssid->ssid_len); if (persistent == NULL || persistent->mode != WPAS_MODE_INFRA) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No matching persistent group stored"); goto disconnect; } - wpa_msg_global(wpa_s->parent, MSG_INFO, + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_PERSISTENT_PSK_FAIL "%d", persistent->id); disconnect: @@ -8016,7 +8356,10 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL, WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent, - params->go_freq, -1, 0, 1, 1); + params->go_freq, wpa_s->p2p_go_vht_center_freq2, + -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, + params->go_ssid_len ? params->go_ssid : NULL, + params->go_ssid_len); } @@ -8043,17 +8386,17 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s, return -1; } - if (wpa_s->parent->p2p_oob_dev_pw_id != + if (wpa_s->p2pdev->p2p_oob_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && - !wpa_s->parent->p2p_oob_dev_pw) { + !wpa_s->p2pdev->p2p_oob_dev_pw) { wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known"); return -1; } res = wpas_ap_wps_add_nfc_pw( - wpa_s, wpa_s->parent->p2p_oob_dev_pw_id, - wpa_s->parent->p2p_oob_dev_pw, - wpa_s->parent->p2p_peer_oob_pk_hash_known ? - wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL); + wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id, + wpa_s->p2pdev->p2p_oob_dev_pw, + wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ? + wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL); if (res) return res; @@ -8071,16 +8414,16 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s, wpa_s->global->p2p_invite_group = wpa_s; persistent = ssid->p2p_persistent_group && - wpas_p2p_get_persistent(wpa_s->parent, + wpas_p2p_get_persistent(wpa_s->p2pdev, params->peer->p2p_device_addr, ssid->ssid, ssid->ssid_len); - wpa_s->parent->pending_invite_ssid_id = -1; + wpa_s->p2pdev->pending_invite_ssid_id = -1; return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr, P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr, ssid->ssid, ssid->ssid_len, ssid->frequency, wpa_s->global->p2p_dev_addr, persistent, 0, - wpa_s->parent->p2p_oob_dev_pw_id); + wpa_s->p2pdev->p2p_oob_dev_pw_id); } @@ -8092,7 +8435,9 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s, "connection handover"); return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL, WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent, - forced_freq, -1, 0, 1, 1); + forced_freq, wpa_s->p2p_go_vht_center_freq2, + -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, + NULL, 0); } @@ -8106,7 +8451,9 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s, "connection handover"); res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL, WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent, - forced_freq, -1, 0, 1, 1); + forced_freq, wpa_s->p2p_go_vht_center_freq2, + -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, + NULL, 0); if (res) return res; @@ -8397,7 +8744,9 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled) } if_addr = wpa_s->pending_interface_addr; - } else + } else if (wpa_s->p2p_mgmt) + if_addr = wpa_s->parent->own_addr; + else if_addr = wpa_s->own_addr; wpa_s->p2p_nfc_tag_enabled = enabled; @@ -8473,14 +8822,115 @@ static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s, static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s) { + struct hostapd_config *conf; + struct p2p_go_neg_results params; + struct csa_settings csa_settings; + struct wpa_ssid *current_ssid = wpa_s->current_ssid; + int old_freq = current_ssid->frequency; + int ret; + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) { wpa_dbg(wpa_s, MSG_DEBUG, "CSA is not enabled"); return -1; } - /* TODO: Add CSA support */ - wpa_dbg(wpa_s, MSG_DEBUG, "Moving GO with CSA is not implemented"); - return -1; + /* + * 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)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P CSA: Failed to select new frequency for GO"); + return -1; + } + + if (current_ssid->frequency == params.freq) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P CSA: Selected same frequency - not moving GO"); + return 0; + } + + conf = hostapd_config_defaults(); + if (!conf) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P CSA: Failed to allocate default config"); + return -1; + } + + current_ssid->frequency = params.freq; + if (wpa_supplicant_conf_ap_ht(wpa_s, current_ssid, conf)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P CSA: Failed to create new GO config"); + ret = -1; + goto out; + } + + if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P CSA: CSA to a different band is not supported"); + ret = -1; + goto out; + } + + os_memset(&csa_settings, 0, sizeof(csa_settings)); + csa_settings.cs_count = P2P_GO_CSA_COUNT; + csa_settings.block_tx = P2P_GO_CSA_BLOCK_TX; + csa_settings.freq_params.freq = params.freq; + csa_settings.freq_params.sec_channel_offset = conf->secondary_channel; + csa_settings.freq_params.ht_enabled = conf->ieee80211n; + csa_settings.freq_params.bandwidth = conf->secondary_channel ? 40 : 20; + + if (conf->ieee80211ac) { + int freq1 = 0, freq2 = 0; + u8 chan, opclass; + + if (ieee80211_freq_to_channel_ext(params.freq, + conf->secondary_channel, + conf->vht_oper_chwidth, + &opclass, &chan) == + NUM_HOSTAPD_MODES) { + wpa_printf(MSG_ERROR, "P2P CSA: Bad freq"); + ret = -1; + goto out; + } + + if (conf->vht_oper_centr_freq_seg0_idx) + freq1 = ieee80211_chan_to_freq( + NULL, opclass, + conf->vht_oper_centr_freq_seg0_idx); + + if (conf->vht_oper_centr_freq_seg1_idx) + freq2 = ieee80211_chan_to_freq( + NULL, opclass, + conf->vht_oper_centr_freq_seg1_idx); + + if (freq1 < 0 || freq2 < 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P CSA: Selected invalid VHT center freqs"); + ret = -1; + goto out; + } + + csa_settings.freq_params.vht_enabled = conf->ieee80211ac; + csa_settings.freq_params.center_freq1 = freq1; + csa_settings.freq_params.center_freq2 = freq2; + + switch (conf->vht_oper_chwidth) { + case VHT_CHANWIDTH_80MHZ: + case VHT_CHANWIDTH_80P80MHZ: + csa_settings.freq_params.bandwidth = 80; + break; + case VHT_CHANWIDTH_160MHZ: + csa_settings.freq_params.bandwidth = 160; + break; + } + } + + ret = ap_switch_channel(wpa_s, &csa_settings); +out: + current_ssid->frequency = old_freq; + hostapd_config_free(conf); + return ret; } @@ -8500,7 +8950,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, NULL)) { + if (wpas_p2p_init_go_params(wpa_s, ¶ms, 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); @@ -8537,6 +8987,13 @@ static void wpas_p2p_move_go(void *eloop_ctx, void *timeout_ctx) wpas_p2p_go_update_common_freqs(wpa_s); + /* Do not move GO in the middle of a CSA */ + if (hostapd_csa_in_progress(wpa_s->ap_iface)) { + wpa_printf(MSG_DEBUG, + "P2P: CSA is in progress - not moving GO"); + return; + } + /* * First, try a channel switch flow. If it is not supported or fails, * take down the GO and bring it up again. @@ -8613,6 +9070,25 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s, P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS && wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) { policy_move = 1; + } else if ((wpa_s->conf->p2p_go_freq_change_policy == + P2P_GO_FREQ_MOVE_SCM_ECSA) && + wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) { + if (!p2p_get_group_num_members(wpa_s->p2p_group)) { + policy_move = 1; + } else if ((wpa_s->drv_flags & + WPA_DRIVER_FLAGS_AP_CSA) && + wpas_p2p_go_clients_support_ecsa(wpa_s)) { + u8 chan; + + /* + * We do not support CSA between bands, so move + * GO only within the same band. + */ + if (wpa_s->ap_iface->current_mode->mode == + ieee80211_freq_to_chan(freqs[i].freq, + &chan)) + policy_move = 1; + } } } @@ -8647,6 +9123,16 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s, return; } + /* + * Do not consider moving GO if it is in the middle of a CSA. When the + * CSA is finished this flow should be retriggered. + */ + if (hostapd_csa_in_progress(wpa_s->ap_iface)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Not initiating a GO frequency change - CSA is in progress"); + return; + } + if (invalid_freq && !wpas_p2p_disallowed_freq(wpa_s->global, freq)) timeout = P2P_GO_FREQ_CHANGE_TIME; else @@ -8726,3 +9212,86 @@ void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s) wpa_s->ap_iface->bss[0]->p2p_group = NULL; wpas_p2p_group_deinit(wpa_s); } + + +int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq, + unsigned int period, unsigned int interval, + unsigned int count) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + u8 *device_types; + size_t dev_types_len; + struct wpabuf *buf; + int ret; + + if (wpa_s->p2p_lo_started) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P Listen offload is already started"); + return 0; + } + + if (wpa_s->global->p2p == NULL || + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) { + wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported"); + return -1; + } + + if (!p2p_supported_freq(wpa_s->global->p2p, freq)) { + wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u", + freq); + return -1; + } + + /* Get device type */ + dev_types_len = (wpa_s->conf->num_sec_device_types + 1) * + WPS_DEV_TYPE_LEN; + device_types = os_malloc(dev_types_len); + if (!device_types) + return -1; + os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN); + os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type, + wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN); + + /* Get Probe Response IE(s) */ + buf = p2p_build_probe_resp_template(p2p, freq); + if (!buf) { + os_free(device_types); + return -1; + } + + ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count, + device_types, dev_types_len, + wpabuf_mhead_u8(buf), wpabuf_len(buf)); + if (ret < 0) + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Failed to start P2P listen offload"); + + os_free(device_types); + wpabuf_free(buf); + + if (ret == 0) { + wpa_s->p2p_lo_started = 1; + + /* Stop current P2P listen if any */ + wpas_stop_listen(wpa_s); + } + + return ret; +} + + +int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s) +{ + int ret; + + if (!wpa_s->p2p_lo_started) + return 0; + + ret = wpa_drv_p2p_lo_stop(wpa_s); + if (ret < 0) + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Failed to stop P2P listen offload"); + + wpa_s->p2p_lo_started = 0; + return ret; +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 56e6834..63910d1 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -34,17 +34,22 @@ struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s, const u8 *peer_dev_addr); int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, - int persistent_group, int auto_join, int join, - int auth, int go_intent, int freq, int persistent_id, - int pd, int ht40, int vht); + 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, + 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 ht40, int vht); + int freq, int vht_center_freq2, int ht40, int vht, + int max_oper_chwidth); 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 ht40, - int vht, const struct p2p_channels *channels, + int force_freq, int neg_freq, + int vht_center_freq2, int ht40, + int vht, int max_oper_chwidth, + const struct p2p_channels *channels, int connection_timeout, int force_scan); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -111,7 +116,8 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, 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 ht40, int vht, int pref_freq); + int vht_center_freq2, int ht40, int vht, + int max_oper_chwidth, int pref_freq); 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, @@ -140,6 +146,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); +int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel); unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *p2p_dev_addr, @@ -199,6 +207,10 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s); void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname); +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); #else /* CONFIG_P2P */ diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant/p2p_supplicant_sd.c index fc07b07..f8675e6 100644 --- a/wpa_supplicant/p2p_supplicant_sd.c +++ b/wpa_supplicant/p2p_supplicant_sd.c @@ -48,7 +48,7 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start, u8 *spos_tmp; /* Offset */ - if (*spos + 2 > end) { + if (end - *spos < 2) { wpa_printf(MSG_DEBUG, "P2P: No room for full " "DNS offset field"); return -1; @@ -74,14 +74,14 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start, return 0; (*spos)++; - if (*spos + len > end) { + if (len > end - *spos) { wpa_printf(MSG_DEBUG, "P2P: Invalid domain name " "sequence - no room for label with length " "%u", len); return -1; } - if (*upos + len + 2 > uend) + if (len + 2 > uend - *upos) return -2; os_memcpy(*upos, *spos, len); @@ -722,11 +722,11 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, if (resp == NULL) return; - while (pos + 1 < end) { + while (end - pos > 1) { wpa_printf(MSG_DEBUG, "P2P: Service Request TLV"); slen = WPA_GET_LE16(pos); pos += 2; - if (pos + slen > end || slen < 2) { + if (slen > end - pos || slen < 2) { wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data " "length"); wpabuf_free(resp); @@ -827,10 +827,10 @@ static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s, u8 svc_len; /* Sanity check fixed length+svc_str */ - if (pos + 6 >= tlv_end) + if (6 >= tlv_end - pos) break; svc_len = pos[6]; - if (pos + svc_len + 10 > tlv_end) + if (svc_len + 10 > tlv_end - pos) break; /* Advertisement ID */ @@ -917,13 +917,13 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, } } - while (pos < end) { + while (end - pos >= 2) { u8 srv_proto, srv_trans_id, status; wpa_printf(MSG_DEBUG, "P2P: Service Response TLV"); slen = WPA_GET_LE16(pos); pos += 2; - if (pos + slen > end || slen < 3) { + if (slen > end - pos || slen < 3) { wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data " "length"); return; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index d7049a1..fb8ebdf 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -36,8 +36,7 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) if (wpa_s->current_ssid == NULL) { wpa_s->current_ssid = ssid; - if (wpa_s->current_ssid != NULL) - wpas_notify_network_changed(wpa_s); + wpas_notify_network_changed(wpa_s); } wpa_supplicant_initiate_eapol(wpa_s); wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured " @@ -60,10 +59,7 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s, wps = 1; *req_type = wpas_wps_get_req_type(ssid); - if (!ssid->eap.phase1) - continue; - - if (os_strstr(ssid->eap.phase1, "pbc=1")) + if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1")) return 2; } @@ -166,6 +162,8 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) if (wpas_update_random_addr_disassoc(wpa_s) < 0) { wpa_msg(wpa_s, MSG_INFO, "Failed to assign random MAC address for a scan"); + wpa_scan_free_params(params); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); radio_work_done(work); return; } @@ -229,12 +227,11 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, } ctx = wpa_scan_clone_params(params); - if (ctx == NULL) - return -1; - - if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) + if (!ctx || + radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) { wpa_scan_free_params(ctx); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); return -1; } @@ -266,14 +263,14 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx) } -int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params, - int interval) +static int +wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params) { int ret; wpa_supplicant_notify_scanning(wpa_s, 1); - ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000); + ret = wpa_drv_sched_scan(wpa_s, params); if (ret) wpa_supplicant_notify_scanning(wpa_s, 0); else @@ -283,7 +280,7 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, } -int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) +static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) { int ret; @@ -429,6 +426,39 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) +{ + struct wpabuf *default_ies = NULL; + u8 ext_capab[18]; + int ext_capab_len; + enum wpa_driver_if_type type = WPA_IF_STATION; + +#ifdef CONFIG_P2P + if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) + type = WPA_IF_P2P_CLIENT; +#endif /* CONFIG_P2P */ + + wpa_drv_get_ext_capa(wpa_s, type); + + ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, + sizeof(ext_capab)); + if (ext_capab_len > 0 && + wpabuf_resize(&default_ies, ext_capab_len) == 0) + 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) + wpas_mbo_scan_ie(wpa_s, default_ies); +#endif /* CONFIG_MBO */ + + if (default_ies) + wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies), + wpabuf_len(default_ies)); + wpabuf_free(default_ies); +} + + static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; @@ -439,6 +469,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) + wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); + else +#endif /* CONFIG_P2P */ + wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); + ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, sizeof(ext_capab)); if (ext_capab_len > 0 && @@ -491,6 +528,19 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) wpabuf_put_buf(extra_ie, wpa_s->fst_ies); #endif /* CONFIG_FST */ +#ifdef CONFIG_MBO + /* Send cellular capabilities for potential MBO STAs */ + if (wpabuf_resize(&extra_ie, 9) == 0) + wpas_mbo_scan_ie(wpa_s, extra_ie); +#endif /* CONFIG_MBO */ + + if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) { + struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]; + + if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0) + wpabuf_put_buf(extra_ie, buf); + } + return extra_ie; } @@ -522,21 +572,6 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) #endif /* CONFIG_P2P */ -static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, - u16 num_modes, - enum hostapd_hw_mode mode) -{ - u16 i; - - for (i = 0; i < num_modes; i++) { - if (modes[i].mode == mode) - return &modes[i]; - } - - return NULL; -} - - static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s, enum hostapd_hw_mode band, struct wpa_driver_scan_params *params) @@ -586,6 +621,12 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, unsigned int i; struct wpa_ssid *ssid; + /* + * For devices with max_ssids greater than 1, leave the last slot empty + * for adding the wildcard scan entry. + */ + max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids; + for (i = 0; i < wpa_s->scan_id_count; i++) { unsigned int j; @@ -840,12 +881,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) * slot for the zero-terminator. */ params.freqs = os_malloc(sizeof(int) * 2); - if (params.freqs == NULL) { - wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed"); - return; + if (params.freqs) { + params.freqs[0] = wpa_s->assoc_freq; + params.freqs[1] = 0; } - params.freqs[0] = wpa_s->assoc_freq; - params.freqs[1] = 0; /* * Reset the reattach flag so that we fall back to full scan if @@ -1016,6 +1055,27 @@ ssid_list_set: } } + if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) { + struct wpa_bss *bss; + + params.bssid = wpa_s->next_scan_bssid; + bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid); + if (bss && bss->ssid_len && params.num_ssids == 1 && + params.ssids[0].ssid_len == 0) { + params.ssids[0].ssid = bss->ssid; + params.ssids[0].ssid_len = bss->ssid_len; + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan a previously specified BSSID " MACSTR + " and SSID %s", + MAC2STR(params.bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len)); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan a previously specified BSSID " MACSTR, + MAC2STR(params.bssid)); + } + } + scan_params = ¶ms; scan: @@ -1076,6 +1136,8 @@ scan: #ifdef CONFIG_INTERWORKING wpa_s->interworking_fast_assoc_tried = 0; #endif /* CONFIG_INTERWORKING */ + if (params.bssid) + os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); } } @@ -1182,6 +1244,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) unsigned int max_sched_scan_ssids; int wildcard = 0; int need_ssids; + struct sched_scan_plan scan_plan; if (!wpa_s->sched_scan_supported) return -1; @@ -1193,6 +1256,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload) return -1; + wpa_s->sched_scan_stop_req = 0; + if (wpa_s->sched_scanning) { wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); return 0; @@ -1271,11 +1336,6 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) if (!ssid || !wpa_s->prev_sched_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); - if (wpa_s->conf->sched_scan_interval) - wpa_s->sched_scan_interval = - wpa_s->conf->sched_scan_interval; - if (wpa_s->sched_scan_interval == 0) - wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; wpa_s->first_sched_scan = 1; ssid = wpa_s->conf->ssid; @@ -1360,14 +1420,51 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) scan_params = ¶ms; scan: - if (ssid || !wpa_s->first_sched_scan) { + wpa_s->sched_scan_timed_out = 0; + + /* + * We cannot support multiple scan plans if the scan request includes + * too many SSID's, so in this case use only the last scan plan and make + * it run infinitely. It will be stopped by the timeout. + */ + if (wpa_s->sched_scan_plans_num == 1 || + (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) { + params.sched_scan_plans = wpa_s->sched_scan_plans; + params.sched_scan_plans_num = wpa_s->sched_scan_plans_num; + } else if (wpa_s->sched_scan_plans_num > 1) { wpa_dbg(wpa_s, MSG_DEBUG, - "Starting sched scan: interval %d timeout %d", - wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); + "Too many SSIDs. Default to using single scheduled_scan plan"); + params.sched_scan_plans = + &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num - + 1]; + params.sched_scan_plans_num = 1; } else { + if (wpa_s->conf->sched_scan_interval) + scan_plan.interval = wpa_s->conf->sched_scan_interval; + else + scan_plan.interval = 10; + + if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) { + wpa_printf(MSG_WARNING, + "Scan interval too long(%u), use the maximum allowed(%u)", + scan_plan.interval, + wpa_s->max_sched_scan_plan_interval); + scan_plan.interval = + wpa_s->max_sched_scan_plan_interval; + } + + scan_plan.iterations = 0; + params.sched_scan_plans = &scan_plan; + params.sched_scan_plans_num = 1; + } + + if (ssid || !wpa_s->first_sched_scan) { wpa_dbg(wpa_s, MSG_DEBUG, - "Starting sched scan: interval %d (no timeout)", - wpa_s->sched_scan_interval); + "Starting sched scan: interval %u timeout %d", + params.sched_scan_plans[0].interval, + wpa_s->sched_scan_timeout); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan (no timeout)"); } wpa_setband_scan_freqs(wpa_s, scan_params); @@ -1381,8 +1478,7 @@ scan: } } - ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params, - wpa_s->sched_scan_interval); + ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params); wpabuf_free(extra_ie); os_free(params.filter_ssids); if (ret) { @@ -1400,9 +1496,12 @@ scan: wpa_s, NULL); wpa_s->first_sched_scan = 0; wpa_s->sched_scan_timeout /= 2; - wpa_s->sched_scan_interval *= 2; - if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) { - wpa_s->sched_scan_interval = 10; + params.sched_scan_plans[0].interval *= 2; + if ((unsigned int) wpa_s->sched_scan_timeout < + params.sched_scan_plans[0].interval || + params.sched_scan_plans[0].interval > + wpa_s->max_sched_scan_plan_interval) { + params.sched_scan_plans[0].interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; } } @@ -1457,6 +1556,9 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s) if (!wpa_s->sched_scanning) return; + if (wpa_s->sched_scanning) + wpa_s->sched_scan_stop_req = 1; + wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan"); eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_supplicant_stop_sched_scan(wpa_s); @@ -1516,20 +1618,7 @@ 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) { - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; + return get_ie((const u8 *) (res + 1), res->ie_len, ie); } @@ -1550,8 +1639,8 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, pos = (const u8 *) (res + 1); end = pos + res->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1587,8 +1676,8 @@ const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res, pos += res->ie_len; end = pos + res->beacon_ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1623,8 +1712,8 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, pos = (const u8 *) (res + 1); end = pos + res->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1832,8 +1921,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, } -static void filter_scan_res(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *res) +void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res) { size_t i, j; @@ -1860,13 +1949,13 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s, /* * Noise floor values to use when we have signal strength - * measurements, but no noise floor measurments. These values were + * measurements, but no noise floor measurements. These values were * measured in an office environment with many APs. */ #define DEFAULT_NOISE_FLOOR_2GHZ (-89) #define DEFAULT_NOISE_FLOOR_5GHZ (-92) -static void scan_snr(struct wpa_scan_res *res) +void scan_snr(struct wpa_scan_res *res) { if (res->flags & WPA_SCAN_NOISE_INVALID) { res->noise = IS_5GHZ(res->freq) ? @@ -1950,8 +2039,8 @@ static unsigned int max_vht80_rate(int snr) } -static void scan_est_throughput(struct wpa_supplicant *wpa_s, - struct wpa_scan_res *res) +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) { enum local_hw_capab capab = wpa_s->hw_capab; int rate; /* max legacy rate in 500 kb/s units */ @@ -2148,6 +2237,9 @@ void scan_only_handler(struct wpa_supplicant *wpa_s, wpa_s->scan_work = NULL; radio_work_done(work); } + + if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state); } @@ -2214,6 +2306,19 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->only_new_results = src->only_new_results; params->low_priority = src->low_priority; + if (src->sched_scan_plans_num > 0) { + params->sched_scan_plans = + os_malloc(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; + } + if (src->mac_addr_rand) { params->mac_addr_rand = src->mac_addr_rand; @@ -2231,6 +2336,17 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->mac_addr_mask = mac_addr + ETH_ALEN; } } + + if (src->bssid) { + u8 *bssid; + + bssid = os_malloc(ETH_ALEN); + if (!bssid) + goto failed; + os_memcpy(bssid, src->bssid, ETH_ALEN); + params->bssid = bssid; + } + return params; failed: @@ -2251,6 +2367,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) os_free((u8 *) params->extra_ies); os_free(params->freqs); os_free(params->filter_ssids); + os_free(params->sched_scan_plans); /* * Note: params->mac_addr_mask points to same memory allocation and @@ -2258,20 +2375,31 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) */ os_free((u8 *) params->mac_addr); + os_free((u8 *) params->bssid); + os_free(params); } int wpas_start_pno(struct wpa_supplicant *wpa_s) { - int ret, interval, prio; + int ret, prio; size_t i, num_ssid, num_match_ssid; struct wpa_ssid *ssid; struct wpa_driver_scan_params params; + struct sched_scan_plan scan_plan; + unsigned int max_sched_scan_ssids; if (!wpa_s->sched_scan_supported) return -1; + if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) + max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; + else + max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; + if (max_sched_scan_ssids < 1) + return -1; + if (wpa_s->pno || wpa_s->pno_sched_pending) return 0; @@ -2292,6 +2420,13 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) } } + if (wpa_s->sched_scan_stop_req) { + wpa_printf(MSG_DEBUG, + "Schedule PNO after previous sched scan has stopped"); + wpa_s->pno_sched_pending = 1; + return 0; + } + os_memset(¶ms, 0, sizeof(params)); num_ssid = num_match_ssid = 0; @@ -2315,10 +2450,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) num_ssid++; } - if (num_ssid > WPAS_MAX_SCAN_SSIDS) { + if (num_ssid > max_sched_scan_ssids) { wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from " - "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid); - num_ssid = WPAS_MAX_SCAN_SSIDS; + "%u", max_sched_scan_ssids, (unsigned int) num_ssid); + num_ssid = max_sched_scan_ssids; } if (num_match_ssid > wpa_s->max_match_sets) { @@ -2361,8 +2496,20 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) if (wpa_s->conf->filter_rssi) params.filter_rssi = wpa_s->conf->filter_rssi; - interval = wpa_s->conf->sched_scan_interval ? - wpa_s->conf->sched_scan_interval : 10; + if (wpa_s->sched_scan_plans_num) { + params.sched_scan_plans = wpa_s->sched_scan_plans; + params.sched_scan_plans_num = wpa_s->sched_scan_plans_num; + } else { + /* Set one scan plan that will run infinitely */ + if (wpa_s->conf->sched_scan_interval) + scan_plan.interval = wpa_s->conf->sched_scan_interval; + else + scan_plan.interval = 10; + + scan_plan.iterations = 0; + params.sched_scan_plans = &scan_plan; + params.sched_scan_plans_num = 1; + } if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels"); @@ -2377,7 +2524,7 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) } } - ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, interval); + ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms); os_free(params.filter_ssids); if (ret == 0) wpa_s->pno = 1; @@ -2395,6 +2542,7 @@ int wpas_stop_pno(struct wpa_supplicant *wpa_s) return 0; ret = wpa_supplicant_stop_sched_scan(wpa_s); + wpa_s->sched_scan_stop_req = 1; wpa_s->pno = 0; wpa_s->pno_sched_pending = 0; @@ -2462,3 +2610,160 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, wpa_s->mac_addr_rand_enable |= type; return 0; } + + +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 */ + + if (scan_work && wpa_s->own_scan_running) { + wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan"); + return wpa_drv_abort_scan(wpa_s); + } + + return 0; +} + + +int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd) +{ + struct sched_scan_plan *scan_plans = NULL; + const char *token, *context = NULL; + unsigned int num = 0; + + if (!cmd) + return -1; + + if (!cmd[0]) { + wpa_printf(MSG_DEBUG, "Clear sched scan plans"); + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = NULL; + wpa_s->sched_scan_plans_num = 0; + return 0; + } + + while ((token = cstr_token(cmd, " ", &context))) { + int ret; + struct sched_scan_plan *scan_plan, *n; + + n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans)); + if (!n) + goto fail; + + scan_plans = n; + scan_plan = &scan_plans[num]; + num++; + + ret = sscanf(token, "%u:%u", &scan_plan->interval, + &scan_plan->iterations); + if (ret <= 0 || ret > 2 || !scan_plan->interval) { + wpa_printf(MSG_ERROR, + "Invalid sched scan plan input: %s", token); + goto fail; + } + + if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) { + wpa_printf(MSG_WARNING, + "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)", + num, scan_plan->interval, + wpa_s->max_sched_scan_plan_interval); + scan_plan->interval = + wpa_s->max_sched_scan_plan_interval; + } + + if (ret == 1) { + scan_plan->iterations = 0; + break; + } + + if (!scan_plan->iterations) { + wpa_printf(MSG_ERROR, + "scan plan %u: Number of iterations cannot be zero", + num); + goto fail; + } + + if (scan_plan->iterations > + wpa_s->max_sched_scan_plan_iterations) { + wpa_printf(MSG_WARNING, + "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)", + num, scan_plan->iterations, + wpa_s->max_sched_scan_plan_iterations); + scan_plan->iterations = + wpa_s->max_sched_scan_plan_iterations; + } + + wpa_printf(MSG_DEBUG, + "scan plan %u: interval=%u iterations=%u", + num, scan_plan->interval, scan_plan->iterations); + } + + if (!scan_plans) { + wpa_printf(MSG_ERROR, "Invalid scan plans entry"); + goto fail; + } + + if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) { + wpa_printf(MSG_ERROR, + "All scan plans but the last must specify a number of iterations"); + goto fail; + } + + wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u", + num, scan_plans[num - 1].interval); + + if (num > wpa_s->max_sched_scan_plans) { + wpa_printf(MSG_WARNING, + "Too many scheduled scan plans (only %u supported)", + wpa_s->max_sched_scan_plans); + wpa_printf(MSG_WARNING, + "Use only the first %u scan plans, and the last one (in infinite loop)", + wpa_s->max_sched_scan_plans - 1); + os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1], + &scan_plans[num - 1], sizeof(*scan_plans)); + num = wpa_s->max_sched_scan_plans; + } + + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = scan_plans; + wpa_s->sched_scan_plans_num = num; + + return 0; + +fail: + os_free(scan_plans); + wpa_printf(MSG_ERROR, "invalid scan plans list"); + return -1; +} + + +/** + * wpas_scan_reset_sched_scan - Reset sched_scan state + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to cancel a running scheduled scan and to reset an + * internal scan state to continue with a regular scan on the following + * wpa_supplicant_req_scan() calls. + */ +void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s) +{ + wpa_s->normal_scans = 0; + if (wpa_s->sched_scanning) { + wpa_s->sched_scan_timed_out = 0; + wpa_s->prev_sched_ssid = NULL; + wpa_supplicant_cancel_sched_scan(wpa_s); + } +} + + +void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s) +{ + /* simulate timeout to restart the sched scan */ + wpa_s->sched_scan_timed_out = 1; + wpa_s->prev_sched_ssid = NULL; + wpa_supplicant_cancel_sched_scan(wpa_s); +} diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index 7650f5a..2aa0a8b 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -39,20 +39,25 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec); void scan_only_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); int wpas_scan_scheduled(struct wpa_supplicant *wpa_s); -int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params, - int interval); -int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s); struct wpa_driver_scan_params * wpa_scan_clone_params(const struct wpa_driver_scan_params *src); void wpa_scan_free_params(struct wpa_driver_scan_params *params); int wpas_start_pno(struct wpa_supplicant *wpa_s); int wpas_stop_pno(struct wpa_supplicant *wpa_s); +void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s); +void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s); void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s, unsigned int type); int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, unsigned int type, const u8 *addr, const u8 *mask); +int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s); +void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res); +void scan_snr(struct wpa_scan_res *res); +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res); +void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s); #endif /* SCAN_H */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index f2e5a43..61fd3b2 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -161,9 +161,10 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s, return; } - if (!(wpa_s->drv_rrm_flags & - WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) || - !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) { + if (!((wpa_s->drv_rrm_flags & + WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) && + (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) && + !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) { wpa_printf(MSG_DEBUG, "RRM: Insufficient RRM support in driver - do not use RRM"); return; @@ -186,6 +187,9 @@ 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; + if (wpa_s->lci) + pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT; + wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2; wpa_s->rrm.rrm_used = 1; } @@ -208,6 +212,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, u8 ext_capab[18]; int ext_capab_len; int skip_auth; +#ifdef CONFIG_MBO + const u8 *mbo; +#endif /* CONFIG_MBO */ if (bss == NULL) { wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for " @@ -416,28 +423,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ -#ifdef CONFIG_HS20 - if (is_hs20_network(wpa_s, ssid, bss)) { - struct wpabuf *hs20; - hs20 = wpabuf_alloc(20); - 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_s->sme.assoc_req_ie) - - wpa_s->sme.assoc_req_ie_len; - if (wpabuf_len(hs20) <= len) { - os_memcpy(wpa_s->sme.assoc_req_ie + - wpa_s->sme.assoc_req_ie_len, - wpabuf_head(hs20), wpabuf_len(hs20)); - wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20); - } - wpabuf_free(hs20); - } - } -#endif /* CONFIG_HS20 */ - #ifdef CONFIG_FST if (wpa_s->fst_ies) { int fst_ies_len = wpabuf_len(wpa_s->fst_ies); @@ -453,6 +438,28 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_FST */ + 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 */ + + if (params.p2p) + wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); + else + wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); + ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, sizeof(ext_capab)); if (ext_capab_len > 0) { @@ -466,6 +473,29 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, os_memcpy(pos, ext_capab, ext_capab_len); } +#ifdef CONFIG_HS20 + if (is_hs20_network(wpa_s, ssid, bss)) { + struct wpabuf *hs20; + + hs20 = wpabuf_alloc(20); + 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_s->sme.assoc_req_ie) - + wpa_s->sme.assoc_req_ie_len; + if (wpabuf_len(hs20) <= len) { + os_memcpy(wpa_s->sme.assoc_req_ie + + wpa_s->sme.assoc_req_ie_len, + wpabuf_head(hs20), wpabuf_len(hs20)); + wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20); + } + wpabuf_free(hs20); + } + } +#endif /* CONFIG_HS20 */ + if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) { struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]; size_t len; @@ -480,7 +510,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } } - sme_auth_handle_rrm(wpa_s, bss); +#ifdef CONFIG_MBO + if (mbo) { + 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); + if (len >= 0) + wpa_s->sme.assoc_req_ie_len += len; + } +#endif /* CONFIG_MBO */ #ifdef CONFIG_SAE if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE && @@ -524,6 +565,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); +#ifdef CONFIG_HS20 + hs20_configure_frame_filters(wpa_s); +#endif /* CONFIG_HS20 */ + #ifdef CONFIG_P2P /* * If multi-channel concurrency is not supported, check for any @@ -632,6 +677,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, radio_remove_works(wpa_s, "sme-connect", 0); } + wpas_abort_ongoing_scan(wpa_s); + cwork = os_zalloc(sizeof(*cwork)); if (cwork == NULL) return; @@ -812,7 +859,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) 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->pending_bssid); + wpa_s->sme.sae.pmkid, wpa_s->pending_bssid); } #endif /* CONFIG_SAE */ @@ -975,8 +1022,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group) params.p2p = 1; - if (wpa_s->parent->set_sta_uapsd) - params.uapsd = wpa_s->parent->sta_uapsd; + if (wpa_s->p2pdev->set_sta_uapsd) + params.uapsd = wpa_s->p2pdev->sta_uapsd; else params.uapsd = -1; @@ -1320,21 +1367,6 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s) } -static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, - u16 num_modes, - enum hostapd_hw_mode mode) -{ - u16 i; - - for (i = 0; i < num_modes; i++) { - if (modes[i].mode == mode) - return &modes[i]; - } - - return NULL; -} - - static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { @@ -1553,8 +1585,10 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx) nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id, wpa_s->sme.sa_query_count + 1, WLAN_SA_QUERY_TR_ID_LEN); - if (nbuf == NULL) + if (nbuf == NULL) { + sme_stop_sa_query(wpa_s); return; + } if (wpa_s->sme.sa_query_count == 0) { /* Starting a new SA Query procedure */ os_get_reltime(&wpa_s->sme.sa_query_start); @@ -1565,6 +1599,7 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx) if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) { wpa_printf(MSG_DEBUG, "Could not generate SA Query ID"); + sme_stop_sa_query(wpa_s); return; } diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in index ea964ce..bc5d49a 100644 --- a/wpa_supplicant/systemd/wpa_supplicant.service.in +++ b/wpa_supplicant/systemd/wpa_supplicant.service.in @@ -5,9 +5,9 @@ Wants=network.target [Service] Type=dbus -BusName=fi.epitest.hostap.WPASupplicant +BusName=@DBUS_INTERFACE@ ExecStart=@BINDIR@/wpa_supplicant -u [Install] WantedBy=multi-user.target -Alias=dbus-fi.epitest.hostap.WPASupplicant.service +Alias=dbus-@DBUS_INTERFACE@.service diff --git a/wpa_supplicant/tests/link_test.c b/wpa_supplicant/tests/link_test.c deleted file mode 100644 index 3bfbed5..0000000 --- a/wpa_supplicant/tests/link_test.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Dummy functions to allow link_test to be linked. The need for these - * functions should be removed to allow IEEE 802.1X/EAPOL authenticator to - * be built outside hostapd. - */ - -#include "includes.h" - -#include "common.h" - - -struct hostapd_data; -struct sta_info; -struct rsn_pmksa_cache_entry; -struct eapol_state_machine; -struct hostapd_eap_user; -struct hostapd_bss_config; -struct hostapd_vlan; - - -struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) -{ - return NULL; -} - - -int ap_for_each_sta(struct hostapd_data *hapd, - int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, - void *ctx), - void *ctx) -{ - return 0; -} - - -void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout) -{ -} - - -int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, - int old_vlanid) -{ - return 0; -} - - -void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, - int success) -{ -} - - -void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, - u8 *buf, size_t len) -{ -} - - -void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) -{ -} - - -void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, - struct eapol_state_machine *eapol) -{ -} - - -const struct hostapd_eap_user * -hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity, - size_t identity_len, int phase2) -{ - return NULL; -} - - -const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id) -{ - return NULL; -} diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c deleted file mode 100644 index f60b182..0000000 --- a/wpa_supplicant/tests/test_eap_sim_common.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Test program for EAP-SIM PRF - * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "eap_common/eap_sim_common.c" - - -static int test_eap_sim_prf(void) -{ - /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */ - u8 xkey[] = { - 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, - 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, - 0xeb, 0x5a, 0x38, 0xb6 - }; - u8 w[] = { - 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, - 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, - 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, - 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, - 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 - }; - u8 buf[40]; - - printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n"); - eap_sim_prf(xkey, buf, sizeof(buf)); - if (memcmp(w, buf, sizeof(w)) != 0) { - printf("eap_sim_prf failed\n"); - return 1; - } - - return 0; -} - - -int main(int argc, char *argv[]) -{ - int errors = 0; - - errors += test_eap_sim_prf(); - - return errors; -} diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c deleted file mode 100644 index 39971f2..0000000 --- a/wpa_supplicant/tests/test_wpa.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Test program for combined WPA authenticator/supplicant - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "../config.h" -#include "rsn_supp/wpa.h" -#include "rsn_supp/wpa_ie.h" -#include "ap/wpa_auth.h" - - -struct wpa { - u8 auth_addr[ETH_ALEN]; - u8 supp_addr[ETH_ALEN]; - u8 psk[PMK_LEN]; - - /* from authenticator */ - u8 auth_eapol_dst[ETH_ALEN]; - u8 *auth_eapol; - size_t auth_eapol_len; - - /* from supplicant */ - u8 *supp_eapol; - size_t supp_eapol_len; - - struct wpa_sm *supp; - struct wpa_authenticator *auth_group; - struct wpa_state_machine *auth; - - struct wpa_ssid ssid; - u8 supp_ie[80]; - size_t supp_ie_len; -}; - - -static int supp_get_bssid(void *ctx, u8 *bssid) -{ - struct wpa *wpa = ctx; - wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); - os_memcpy(bssid, wpa->auth_addr, ETH_ALEN); - return 0; -} - - -static void supp_set_state(void *ctx, enum wpa_states state) -{ - wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state); -} - - -static void auth_eapol_rx(void *eloop_data, void *user_ctx) -{ - struct wpa *wpa = eloop_data; - - wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame"); - wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol, - wpa->supp_eapol_len); -} - - -static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, - size_t len) -{ - struct wpa *wpa = ctx; - - wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " - "len=%lu)", - __func__, MAC2STR(dest), proto, (unsigned long) len); - - os_free(wpa->supp_eapol); - wpa->supp_eapol = os_malloc(len); - if (wpa->supp_eapol == NULL) - return -1; - os_memcpy(wpa->supp_eapol, buf, len); - wpa->supp_eapol_len = len; - eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL); - - return 0; -} - - -static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, - u16 data_len, size_t *msg_len, void **data_pos) -{ - struct ieee802_1x_hdr *hdr; - - wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", - __func__, type, data_len); - - *msg_len = sizeof(*hdr) + data_len; - hdr = os_malloc(*msg_len); - if (hdr == NULL) - return NULL; - - hdr->version = 2; - hdr->type = type; - hdr->length = host_to_be16(data_len); - - if (data) - os_memcpy(hdr + 1, data, data_len); - else - os_memset(hdr + 1, 0, data_len); - - if (data_pos) - *data_pos = hdr + 1; - - return (u8 *) hdr; -} - - -static int supp_get_beacon_ie(void *ctx) -{ - struct wpa *wpa = ctx; - const u8 *ie; - size_t ielen; - - wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); - - ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen); - if (ie == NULL || ielen < 1) - return -1; - if (ie[0] == WLAN_EID_RSN) - return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]); - return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]); -} - - -static int supp_set_key(void *ctx, enum wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " - "set_tx=%d)", - __func__, alg, MAC2STR(addr), key_idx, set_tx); - wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); - wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len); - return 0; -} - - -static int supp_mlme_setprotection(void *ctx, const u8 *addr, - int protection_type, int key_type) -{ - wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " - "key_type=%d)", - __func__, MAC2STR(addr), protection_type, key_type); - return 0; -} - - -static void supp_cancel_auth_timeout(void *ctx) -{ - wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); -} - - -static int supp_init(struct wpa *wpa) -{ - struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return -1; - - ctx->ctx = wpa; - ctx->msg_ctx = wpa; - ctx->set_state = supp_set_state; - ctx->get_bssid = supp_get_bssid; - ctx->ether_send = supp_ether_send; - ctx->get_beacon_ie = supp_get_beacon_ie; - ctx->alloc_eapol = supp_alloc_eapol; - ctx->set_key = supp_set_key; - ctx->mlme_setprotection = supp_mlme_setprotection; - ctx->cancel_auth_timeout = supp_cancel_auth_timeout; - wpa->supp = wpa_sm_init(ctx); - if (wpa->supp == NULL) { - wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); - return -1; - } - - wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr); - wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1); - wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); - wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); - wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); - wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); - wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN); - - wpa->supp_ie_len = sizeof(wpa->supp_ie); - if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie, - &wpa->supp_ie_len) < 0) { - wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" - " failed"); - return -1; - } - - wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr); - - return 0; -} - - -static void auth_logger(void *ctx, const u8 *addr, logger_level level, - const char *txt) -{ - if (addr) - wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", - MAC2STR(addr), txt); - else - wpa_printf(MSG_DEBUG, "AUTH: %s", txt); -} - - -static void supp_eapol_rx(void *eloop_data, void *user_ctx) -{ - struct wpa *wpa = eloop_data; - - wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame"); - wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol, - wpa->auth_eapol_len); -} - - -static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, - size_t data_len, int encrypt) -{ - struct wpa *wpa = ctx; - - wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " - "encrypt=%d)", - __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); - - os_free(wpa->auth_eapol); - wpa->auth_eapol = os_malloc(data_len); - if (wpa->auth_eapol == NULL) - return -1; - os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN); - os_memcpy(wpa->auth_eapol, data, data_len); - wpa->auth_eapol_len = data_len; - eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL); - - return 0; -} - - -static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) -{ - struct wpa *wpa = ctx; - wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", - __func__, MAC2STR(addr), prev_psk); - if (prev_psk) - return NULL; - return wpa->psk; -} - - -static int auth_init_group(struct wpa *wpa) -{ - struct wpa_auth_config conf; - struct wpa_auth_callbacks cb; - - wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); - - os_memset(&conf, 0, sizeof(conf)); - conf.wpa = 2; - conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; - conf.wpa_pairwise = WPA_CIPHER_CCMP; - conf.rsn_pairwise = WPA_CIPHER_CCMP; - conf.wpa_group = WPA_CIPHER_CCMP; - conf.eapol_version = 2; - - os_memset(&cb, 0, sizeof(cb)); - cb.ctx = wpa; - cb.logger = auth_logger; - cb.send_eapol = auth_send_eapol; - cb.get_psk = auth_get_psk; - - wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb); - if (wpa->auth_group == NULL) { - wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); - return -1; - } - - return 0; -} - - -static int auth_init(struct wpa *wpa) -{ - wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL); - if (wpa->auth == NULL) { - wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); - return -1; - } - - if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie, - wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) { - wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); - return -1; - } - - wpa_auth_sm_event(wpa->auth, WPA_ASSOC); - - wpa_auth_sta_associated(wpa->auth_group, wpa->auth); - - return 0; -} - - -static void deinit(struct wpa *wpa) -{ - wpa_auth_sta_deinit(wpa->auth); - wpa_sm_deinit(wpa->supp); - wpa_deinit(wpa->auth_group); - os_free(wpa->auth_eapol); - wpa->auth_eapol = NULL; - os_free(wpa->supp_eapol); - wpa->supp_eapol = NULL; -} - - -int main(int argc, char *argv[]) -{ - struct wpa wpa; - - if (os_program_init()) - return -1; - - os_memset(&wpa, 0, sizeof(wpa)); - os_memset(wpa.auth_addr, 0x12, ETH_ALEN); - os_memset(wpa.supp_addr, 0x32, ETH_ALEN); - os_memset(wpa.psk, 0x44, PMK_LEN); - - wpa_debug_level = 0; - wpa_debug_show_keys = 1; - - if (eloop_init()) { - wpa_printf(MSG_ERROR, "Failed to initialize event loop"); - return -1; - } - - if (auth_init_group(&wpa) < 0) - return -1; - - if (supp_init(&wpa) < 0) - return -1; - - if (auth_init(&wpa) < 0) - return -1; - - wpa_printf(MSG_DEBUG, "Starting eloop"); - eloop_run(); - wpa_printf(MSG_DEBUG, "eloop done"); - - deinit(&wpa); - - eloop_destroy(); - - os_program_deinit(); - - return 0; -} diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h index 5171b16..0d15ad0 100644 --- a/wpa_supplicant/wmm_ac.h +++ b/wpa_supplicant/wmm_ac.h @@ -88,7 +88,7 @@ enum ts_dir_idx { */ struct wmm_ac_addts_request { /* - * dialog token - Used to link the recived ADDTS response with this + * dialog token - Used to link the received ADDTS response with this * saved ADDTS request when ADDTS response is being handled */ u8 dialog_token; diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 954de67..1b3409c 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -24,6 +24,7 @@ #define MAX_TFS_IE_LEN 1024 #define WNM_MAX_NEIGHBOR_REPORT 10 +#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */ /* get the TFS IE from driver */ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, @@ -37,12 +38,14 @@ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, /* set the TFS IE to driver */ static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, - const u8 *addr, u8 *buf, u16 *buf_len, + const u8 *addr, const u8 *buf, u16 buf_len, enum wnm_oper oper) { + u16 len = buf_len; + wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); - return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); + return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); } @@ -137,6 +140,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, if (res < 0) wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " "(action=%d, intval=%d)", action, intval); + else + wpa_s->wnmsleep_used = 1; os_free(wnmsleep_ie); os_free(wnmtfs_ie); @@ -147,8 +152,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, - u8 *tfsresp_ie_start, - u8 *tfsresp_ie_end) + const u8 *tfsresp_ie_start, + const u8 *tfsresp_ie_end) { wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, wpa_s->bssid, NULL, NULL); @@ -164,7 +169,7 @@ static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, /* pass the TFS Resp IE(s) to driver for processing */ if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, tfsresp_ie_start, - &tfsresp_ie_len, + tfsresp_ie_len, WNM_SLEEP_TFS_RESP_IE_SET)) wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); } @@ -187,8 +192,14 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, end = ptr + key_len_total; wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); - while (ptr + 1 < end) { - if (ptr + 2 + ptr[1] > end) { + if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { + wpa_msg(wpa_s, MSG_INFO, + "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); + return; + } + + while (end - ptr > 1) { + if (2 + ptr[1] > end - ptr) { wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " "length"); if (end > ptr) { @@ -239,14 +250,20 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | * WNM-Sleep Mode IE | TFS Response IE */ - u8 *pos = (u8 *) frm; /* point to payload after the action field */ + const u8 *pos = frm; /* point to payload after the action field */ u16 key_len_total; struct wnm_sleep_element *wnmsleep_ie = NULL; /* multiple TFS Resp IE (assuming consecutive) */ - u8 *tfsresp_ie_start = NULL; - u8 *tfsresp_ie_end = NULL; + const u8 *tfsresp_ie_start = NULL; + const u8 *tfsresp_ie_end = NULL; size_t left; + if (!wpa_s->wnmsleep_used) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association"); + return; + } + if (len < 3) return; key_len_total = WPA_GET_LE16(frm + 1); @@ -259,14 +276,14 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, return; } pos += 3 + key_len_total; - while (pos - frm < len) { + while (pos - frm + 1 < len) { u8 ie_len = *(pos + 1); - if (pos + 2 + ie_len > frm + len) { + if (2 + ie_len > frm + len - pos) { wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); break; } wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); - if (*pos == WLAN_EID_WNMSLEEP) + if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) wnmsleep_ie = (struct wnm_sleep_element *) pos; else if (*pos == WLAN_EID_TFS_RESP) { if (!tfsresp_ie_start) @@ -413,6 +430,7 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) { struct wpa_bss *bss = wpa_s->current_bss; const char *country = NULL; + int freq; if (bss) { const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); @@ -421,7 +439,21 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) country = (const char *) (elem + 2); } - return ieee80211_chan_to_freq(country, op_class, chan); + freq = ieee80211_chan_to_freq(country, op_class, chan); + if (freq <= 0 && op_class == 0) { + /* + * Some APs do not advertise correct operating class + * information. Try to determine the most likely operating + * frequency based on the channel number. + */ + if (chan >= 1 && chan <= 13) + freq = 2407 + chan * 5; + else if (chan == 14) + freq = 2484; + else if (chan >= 36 && chan <= 169) + freq = 5000 + chan * 5; + } + return freq; } @@ -468,7 +500,7 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, static struct wpa_bss * -compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) +compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) { u8 i; @@ -476,7 +508,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) struct wpa_bss *target; if (!bss) - return 0; + return NULL; wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), bss->level); @@ -501,6 +533,19 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) continue; } + if (age_secs) { + struct os_reltime now; + + if (os_get_reltime(&now) == 0 && + os_reltime_expired(&now, &target->last_update, + age_secs)) { + wpa_printf(MSG_DEBUG, + "Candidate BSS is more than %ld seconds old", + age_secs); + continue; + } + } + if (bss->ssid_len != target->ssid_len || os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { /* @@ -515,6 +560,25 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) continue; } + if (wpa_s->current_ssid && + !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, + 1)) { + wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR + " (pref %d) does not match the current network profile", + MAC2STR(nei->bssid), + nei->preference_present ? nei->preference : + -1); + continue; + } + + if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { + wpa_printf(MSG_DEBUG, + "MBO: Candidate BSS " MACSTR + " retry delay is not over yet", + MAC2STR(nei->bssid)); + continue; + } + if (target->level < bss->level && target->level < -80) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not have sufficient signal level (%d)", @@ -536,12 +600,190 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) } +static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid) +{ + const u8 *ie_a, *ie_b; + + if (!a || !b) + return 0; + + ie_a = wpa_bss_get_ie(a, eid); + ie_b = wpa_bss_get_ie(b, eid); + + if (!ie_a || !ie_b || ie_a[1] != ie_b[1]) + return 0; + + return os_memcmp(ie_a, ie_b, ie_a[1]) == 0; +} + + +static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + u32 info = 0; + + info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH; + + /* + * Leave the security and key scope bits unset to indicate that the + * security information is not available. + */ + + if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT) + info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; + if (bss->caps & WLAN_CAPABILITY_QOS) + info |= NEI_REP_BSSID_INFO_QOS; + if (bss->caps & WLAN_CAPABILITY_APSD) + info |= NEI_REP_BSSID_INFO_APSD; + if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT) + info |= NEI_REP_BSSID_INFO_RM; + if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK) + info |= NEI_REP_BSSID_INFO_DELAYED_BA; + if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK) + info |= NEI_REP_BSSID_INFO_IMM_BA; + if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN)) + info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN; + if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP)) + info |= NEI_REP_BSSID_INFO_HT; + + return info; +} + + +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) +{ + u8 *pos = buf; + + if (len < 18) { + wpa_printf(MSG_DEBUG, + "WNM: Not enough room for Neighbor Report element"); + return -1; + } + + *pos++ = 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; +} + + +static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, u8 *buf, size_t len, + u8 pref) +{ + const u8 *ie; + u8 op_class, chan; + int sec_chan = 0, vht = 0; + enum phy_type phy_type; + u32 info; + struct ieee80211_ht_operation *ht_oper = NULL; + struct ieee80211_vht_operation *vht_oper = NULL; + + ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); + if (ie && ie[1] >= 2) { + ht_oper = (struct ieee80211_ht_operation *) (ie + 2); + + if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) + sec_chan = 1; + else if (ht_oper->ht_param & + HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) + sec_chan = -1; + } + + ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); + if (ie && ie[1] >= 1) { + vht_oper = (struct ieee80211_vht_operation *) (ie + 2); + + if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ || + vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ || + vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ) + vht = vht_oper->vht_op_info_chwidth; + } + + if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, + &chan) == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_DEBUG, + "WNM: Cannot determine operating class and channel"); + return -2; + } + + phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), + (vht_oper != NULL)); + if (phy_type == PHY_TYPE_UNSPECIFIED) { + wpa_printf(MSG_DEBUG, + "WNM: Cannot determine BSS phy type for Neighbor Report"); + return -2; + } + + info = wnm_get_bss_info(wpa_s, bss); + + return wnm_add_nei_rep(buf, len, 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) +{ + u8 *pos = buf; + unsigned int i, pref = 255; + struct os_reltime now; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (!ssid) + return 0; + + /* + * TODO: Define when scan results are no longer valid for the candidate + * list. + */ + os_get_reltime(&now); + if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) + return 0; + + wpa_printf(MSG_DEBUG, + "WNM: Add candidate list to BSS Transition Management Response frame"); + for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { + 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 (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; +} + + 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) { - u8 buf[1000], *pos; + u8 buf[2000], *pos; struct ieee80211_mgmt *mgmt; size_t len; int res; @@ -581,6 +823,17 @@ static void wnm_send_bss_transition_mgmt_resp( pos += ETH_ALEN; } + if (status == WNM_BSS_TM_ACCEPT) + pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); + +#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); + } +#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, @@ -593,6 +846,41 @@ static void wnm_send_bss_transition_mgmt_resp( } +static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, struct wpa_ssid *ssid, + int after_new_scan) +{ + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Transition to BSS " MACSTR + " based on BSS Transition Management Request (old BSSID " + MACSTR " after_new_scan=%d)", + MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); + + /* Send the BSS Management Response - Accept */ + if (wpa_s->wnm_reply) { + 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); + } + + if (bss == wpa_s->current_bss) { + wpa_printf(MSG_DEBUG, + "WNM: Already associated with the preferred candidate"); + wnm_deallocate_memory(wpa_s); + return; + } + + wpa_s->reassociate = 1; + wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); + wpa_supplicant_connect(wpa_s, bss, ssid); + wnm_deallocate_memory(wpa_s); +} + + int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) { struct wpa_bss *bss; @@ -602,6 +890,8 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) if (!wpa_s->wnm_neighbor_report_elements) return 0; + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Process scan results for BSS Transition Management"); if (os_reltime_before(&wpa_s->wnm_cand_valid_until, &wpa_s->scan_trigger_time)) { wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); @@ -617,7 +907,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); + bss = compare_scan_neighbor_results(wpa_s, 0); if (!bss) { wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; @@ -625,24 +915,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) } /* Associate to the network */ - /* Send the BSS Management Response - Accept */ - if (wpa_s->wnm_reply) { - wpa_s->wnm_reply = 0; - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - WNM_BSS_TM_ACCEPT, - 0, bss->bssid); - } - - if (bss == wpa_s->current_bss) { - wpa_printf(MSG_DEBUG, - "WNM: Already associated with the preferred candidate"); - return 1; - } - - wpa_s->reassociate = 1; - wpa_supplicant_connect(wpa_s, bss, ssid); - wnm_deallocate_memory(wpa_s); + wnm_bss_tm_connect(wpa_s, bss, ssid, 1); return 1; send_bss_resp_fail: @@ -783,14 +1056,90 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) } +static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) +{ + struct wpa_scan_results *scan_res; + struct wpa_bss *bss; + struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 i, found = 0; + size_t j; + + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Fetch current scan results from the driver for checking transition candidates"); + scan_res = wpa_drv_get_scan_results2(wpa_s); + if (!scan_res) { + wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); + return 0; + } + + if (scan_res->fetch_time.sec == 0) + os_get_reltime(&scan_res->fetch_time); + + filter_scan_res(wpa_s, scan_res); + + for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { + struct neighbor_report *nei; + + nei = &wpa_s->wnm_neighbor_report_elements[i]; + if (nei->preference_present && nei->preference == 0) + continue; + + for (j = 0; j < scan_res->num; j++) { + struct wpa_scan_res *res; + const u8 *ssid_ie; + + res = scan_res->res[j]; + if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || + res->age > WNM_SCAN_RESULT_AGE * 1000) + continue; + bss = wpa_s->current_bss; + ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); + if (bss && ssid_ie && + (bss->ssid_len != ssid_ie[1] || + os_memcmp(bss->ssid, ssid_ie + 2, + bss->ssid_len) != 0)) + continue; + + /* Potential candidate found */ + found = 1; + scan_snr(res); + scan_est_throughput(wpa_s, res); + wpa_bss_update_scan_res(wpa_s, res, + &scan_res->fetch_time); + } + } + + wpa_scan_results_free(scan_res); + if (!found) { + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: No transition candidate matches existing scan results"); + return 0; + } + + bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE); + if (!bss) { + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Comparison of scan results against transition candidates did not find matches"); + return 0; + } + + /* Associate to the network */ + wnm_bss_tm_connect(wpa_s, bss, ssid, 0); + return 1; +} + + static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) { unsigned int beacon_int; u8 valid_int; +#ifdef CONFIG_MBO + const u8 *vendor; +#endif /* CONFIG_MBO */ - if (pos + 5 > end) + if (end - pos < 5) return; if (wpa_s->current_bss) @@ -810,10 +1159,23 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, valid_int); +#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) + if (wpa_s->reject_btm_req_reason) { + 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); + return; + } +#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ + pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { - if (pos + 12 > end) { + if (end - pos < 12) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); return; } @@ -824,7 +1186,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; - if (pos + 1 > end || pos + 1 + pos[0] > end) { + if (end - pos < 1 || 1 + pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); return; @@ -849,6 +1211,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } } +#ifdef CONFIG_MBO + vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); + if (vendor) + wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); +#endif /* CONFIG_MBO */ + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { unsigned int valid_ms; @@ -860,7 +1228,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, if (wpa_s->wnm_neighbor_report_elements == NULL) return; - while (pos + 2 <= end && + while (end - pos >= 2 && wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) { u8 tag = *pos++; @@ -868,7 +1236,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", tag); - if (pos + len > end) { + if (len > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Truncated request"); return; } @@ -877,11 +1245,22 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, rep = &wpa_s->wnm_neighbor_report_elements[ wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); + wpa_s->wnm_num_neighbor_report++; } pos += len; - wpa_s->wnm_num_neighbor_report++; } + + if (!wpa_s->wnm_num_neighbor_report) { + wpa_printf(MSG_DEBUG, + "WNM: Candidate list included bit is set, but no candidates found"); + wnm_send_bss_transition_mgmt_resp( + wpa_s, wpa_s->wnm_dialog_token, + WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, + 0, NULL); + return; + } + wnm_sort_cand_list(wpa_s); wnm_dump_cand_list(wpa_s); valid_ms = valid_int * beacon_int * 128 / 125; @@ -895,6 +1274,20 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_cand_valid_until.usec %= 1000000; os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); + /* + * Fetch the latest scan results from the kernel and check for + * candidates based on those results first. This can help in + * finding more up-to-date information should the driver has + * done some internal scanning operations after the last scan + * result update in wpa_supplicant. + */ + if (wnm_fetch_scan_results(wpa_s) > 0) + return; + + /* + * Try to use previously received scan results, if they are + * recent enough to use for a connection. + */ if (wpa_s->last_scan_res_used > 0) { struct os_reltime now; @@ -910,6 +1303,14 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } wnm_set_scan_freqs(wpa_s); + if (wpa_s->wnm_num_neighbor_report == 1) { + os_memcpy(wpa_s->next_scan_bssid, + wpa_s->wnm_neighbor_report_elements[0].bssid, + ETH_ALEN); + wpa_printf(MSG_DEBUG, + "WNM: Scan only for a specific BSSID since there is only a single candidate " + MACSTR, MAC2STR(wpa_s->next_scan_bssid)); + } wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; @@ -927,16 +1328,17 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, - u8 query_reason) + u8 query_reason, int cand_list) { - u8 buf[1000], *pos; + u8 buf[2000], *pos; struct ieee80211_mgmt *mgmt; size_t len; int ret; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " - MACSTR " query_reason=%u", - MAC2STR(wpa_s->bssid), query_reason); + MACSTR " query_reason=%u%s", + MAC2STR(wpa_s->bssid), query_reason, + cand_list ? " candidate list" : ""); mgmt = (struct ieee80211_mgmt *) buf; os_memset(&buf, 0, sizeof(buf)); @@ -951,6 +1353,9 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, mgmt->u.action.u.bss_tm_query.query_reason = query_reason; pos = mgmt->u.action.u.bss_tm_query.variable; + if (cand_list) + pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); + len = pos - (u8 *) &mgmt->u.action.category; ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, @@ -971,7 +1376,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, pos = data; end = data + len; - while (pos + 1 < end) { + while (end - pos > 1) { ie = *pos++; ie_len = *pos++; wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", @@ -1009,7 +1414,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, url = NULL; osu_method = 1; } else { - if (pos + url_len + 1 > ie_end) { + if (url_len + 1 > ie_end - pos) { wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", url_len, (int) (ie_end - pos)); @@ -1048,7 +1453,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, "Imminent - Reason Code %u " "Re-Auth Delay %u URL Length %u", code, reauth_delay, url_len); - if (pos + url_len > ie_end) + if (url_len > ie_end - pos) break; url = os_malloc(url_len + 1); if (url == NULL) diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index 8de4348..81d8153 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -56,7 +56,7 @@ 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); + u8 query_reason, int cand_list); void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 7ddae3d..a848b77 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - command line interface for wpa_supplicant daemon - * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -14,6 +14,7 @@ #include <dirent.h> #endif /* CONFIG_CTRL_IFACE_UNIX */ +#include "common/cli.h" #include "common/wpa_ctrl.h" #include "utils/common.h" #include "utils/eloop.h" @@ -28,43 +29,13 @@ static const char *const wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors"; - - -static const char *const wpa_cli_license = -"This software may be distributed under the terms of the BSD license.\n" -"See README for more details.\n"; - -static const char *const wpa_cli_full_license = -"This software may be distributed under the terms of the BSD license.\n" -"\n" -"Redistribution and use in source and binary forms, with or without\n" -"modification, are permitted provided that the following conditions are\n" -"met:\n" -"\n" -"1. Redistributions of source code must retain the above copyright\n" -" notice, this list of conditions and the following disclaimer.\n" -"\n" -"2. Redistributions in binary form must reproduce the above copyright\n" -" notice, this list of conditions and the following disclaimer in the\n" -" documentation and/or other materials provided with the distribution.\n" -"\n" -"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" -" names of its contributors may be used to endorse or promote products\n" -" derived from this software without specific prior written permission.\n" -"\n" -"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" -"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" -"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" -"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" -"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" -"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" -"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" -"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" -"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" -"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" -"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" -"\n"; +"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors"; + +#define VENDOR_ELEM_FRAME_ID \ + " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \ + "3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \ + "7: GO Neg Resp, 8: GO Neg Conf, 9: Inv Req, 10: Inv Resp, " \ + "11: Assoc Req (P2P), 12: Assoc Resp (P2P)" static struct wpa_ctrl *ctrl_conn; static struct wpa_ctrl *mon_conn; @@ -84,11 +55,6 @@ static int ping_interval = 5; static int interactive = 0; static char *ifname_prefix = NULL; -struct cli_txt_entry { - struct dl_list list; - char *txt; -}; - static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ @@ -124,168 +90,6 @@ static void usage(void) } -static void cli_txt_list_free(struct cli_txt_entry *e) -{ - dl_list_del(&e->list); - os_free(e->txt); - os_free(e); -} - - -static void cli_txt_list_flush(struct dl_list *list) -{ - struct cli_txt_entry *e; - while ((e = dl_list_first(list, struct cli_txt_entry, list))) - cli_txt_list_free(e); -} - - -static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list, - const char *txt) -{ - struct cli_txt_entry *e; - dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { - if (os_strcmp(e->txt, txt) == 0) - return e; - } - return NULL; -} - - -static void cli_txt_list_del(struct dl_list *txt_list, const char *txt) -{ - struct cli_txt_entry *e; - e = cli_txt_list_get(txt_list, txt); - if (e) - cli_txt_list_free(e); -} - - -static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt) -{ - u8 addr[ETH_ALEN]; - char buf[18]; - if (hwaddr_aton(txt, addr) < 0) - return; - os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - cli_txt_list_del(txt_list, buf); -} - - -#ifdef CONFIG_P2P -static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt, - int separator) -{ - const char *end; - char *buf; - end = os_strchr(txt, separator); - if (end == NULL) - end = txt + os_strlen(txt); - buf = dup_binstr(txt, end - txt); - if (buf == NULL) - return; - cli_txt_list_del(txt_list, buf); - os_free(buf); -} -#endif /* CONFIG_P2P */ - - -static int cli_txt_list_add(struct dl_list *txt_list, const char *txt) -{ - struct cli_txt_entry *e; - e = cli_txt_list_get(txt_list, txt); - if (e) - return 0; - e = os_zalloc(sizeof(*e)); - if (e == NULL) - return -1; - e->txt = os_strdup(txt); - if (e->txt == NULL) { - os_free(e); - return -1; - } - dl_list_add(txt_list, &e->list); - return 0; -} - - -#ifdef CONFIG_P2P -static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt) -{ - u8 addr[ETH_ALEN]; - char buf[18]; - if (hwaddr_aton(txt, addr) < 0) - return -1; - os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - return cli_txt_list_add(txt_list, buf); -} -#endif /* CONFIG_P2P */ - - -static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt, - int separator) -{ - const char *end; - char *buf; - int ret; - end = os_strchr(txt, separator); - if (end == NULL) - end = txt + os_strlen(txt); - buf = dup_binstr(txt, end - txt); - if (buf == NULL) - return -1; - ret = cli_txt_list_add(txt_list, buf); - os_free(buf); - return ret; -} - - -static char ** cli_txt_list_array(struct dl_list *txt_list) -{ - unsigned int i, count = dl_list_len(txt_list); - char **res; - struct cli_txt_entry *e; - - res = os_calloc(count + 1, sizeof(char *)); - if (res == NULL) - return NULL; - - i = 0; - dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { - res[i] = os_strdup(e->txt); - if (res[i] == NULL) - break; - i++; - } - - return res; -} - - -static int get_cmd_arg_num(const char *str, int pos) -{ - int arg = 0, i; - - for (i = 0; i <= pos; i++) { - if (str[i] != ' ') { - arg++; - while (i <= pos && str[i] != ' ') - i++; - } - } - - if (arg > 0) - arg--; - return arg; -} - - -static int str_starts(const char *src, const char *match) -{ - return os_strncmp(src, match, os_strlen(match)) == 0; -} - - static int wpa_cli_show_event(const char *event) { const char *start; @@ -452,36 +256,6 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) } -static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, - char *argv[]) -{ - int i, res; - char *pos, *end; - - pos = buf; - end = buf + buflen; - - res = os_snprintf(pos, end - pos, "%s", cmd); - if (os_snprintf_error(end - pos, res)) - goto fail; - pos += res; - - for (i = 0; i < argc; i++) { - res = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, res)) - goto fail; - pos += res; - } - - buf[buflen - 1] = '\0'; - return 0; - -fail: - printf("Too long command\n"); - return -1; -} - - static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args, int argc, char *argv[]) { @@ -581,7 +355,7 @@ static char ** wpa_cli_complete_help(const char *str, int pos) static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license); + printf("%s\n\n%s\n", wpa_cli_version, cli_full_license); return 0; } @@ -677,7 +451,10 @@ static char ** wpa_cli_complete_set(const char *str, int pos) "tdls_external_control", "osu_dir", "wowlan_triggers", "p2p_search_delay", "mac_addr", "rand_addr_lifetime", "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", - "reassoc_same_bss_optim", "wps_priority" + "reassoc_same_bss_optim", "wps_priority", +#ifdef CONFIG_TESTING_OPTIONS + "ignore_auth_resp", +#endif /* CONFIG_TESTING_OPTIONS */ }; int i, num_fields = ARRAY_SIZE(fields); @@ -705,6 +482,13 @@ static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); +} + + static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); @@ -1548,7 +1332,7 @@ 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", + "freq_list", "max_oper_chwidth", #ifdef IEEE8021X_EAPOL "eap", "identity", "anonymous_identity", "password", "ca_cert", "ca_path", "client_cert", "private_key", "private_key_passwd", @@ -1606,7 +1390,7 @@ static const char *network_fields[] = { #ifdef CONFIG_HS20 "update_identifier", #endif /* CONFIG_HS20 */ - "mac_addr" + "mac_addr", "pbss", "wps_disabled" }; @@ -1764,6 +1548,13 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_abort_scan(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ABORT_SCAN"); +} + + static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv); @@ -1804,6 +1595,48 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, } +static char ** wpa_cli_complete_get_capability(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + const char *fields[] = { + "eap", "pairwise", "group", "group_mgmt", "key_mgmt", + "proto", "auth_alg", "modes", "channels", "freq", +#ifdef CONFIG_TDLS + "tdls", +#endif /* CONFIG_TDLS */ +#ifdef CONFIG_ERP + "erp", +#endif /* CONFIG_ERP */ +#ifdef CONFIG_FIPS + "fips", +#endif /* CONFIG_FIPS */ +#ifdef CONFIG_ACS + "acs", +#endif /* CONFIG_ACS */ + }; + int i, num_fields = ARRAY_SIZE(fields); + char **res = NULL; + + if (arg == 1) { + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(fields[i]); + if (res[i] == NULL) + return res; + } + } + if (arg == 2) { + res = os_calloc(1 + 1, sizeof(char *)); + if (res == NULL) + return NULL; + res[0] = os_strdup("strict"); + } + return res; +} + + static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl) { printf("Available interfaces:\n"); @@ -1866,14 +1699,15 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, /* * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB - * <driver_param>TAB<bridge_name>[TAB<create>] + * <driver_param>TAB<bridge_name>[TAB<create>[TAB<type>]] */ res = os_snprintf(cmd, sizeof(cmd), - "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s", + "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", argv[0], argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", - argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : ""); + argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "", + argc > 7 ? argv[7] : ""); if (os_snprintf_error(sizeof(cmd), res)) return -1; cmd[sizeof(cmd) - 1] = '\0'; @@ -1913,6 +1747,12 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, printf("Not connected to hostapd - command dropped.\n"); return -1; } + if (ifname_prefix) { + os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", + ifname_prefix, cmd); + buf[sizeof(buf) - 1] = '\0'; + cmd = buf; + } len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb); @@ -2022,6 +1862,20 @@ static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc, return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv); } + +static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv); +} + #endif /* CONFIG_MESH */ @@ -2141,6 +1995,13 @@ static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv); +} + + static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2477,6 +2338,27 @@ 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); } + +static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR_ELEM_ADD", 2, argc, argv); +} + + +static int wpa_cli_cmd_vendor_elem_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR_ELEM_GET", 1, argc, argv); +} + + +static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv); +} + #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY @@ -2719,6 +2601,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv); +} + + static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2823,6 +2712,20 @@ static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv); +} + + +static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv); +} + + enum wpa_cli_cmd_flags { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 @@ -2880,6 +2783,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "get", wpa_cli_cmd_get, wpa_cli_complete_get, cli_cmd_flag_none, "<name> = get information" }, + { "driver_flags", wpa_cli_cmd_driver_flags, NULL, + cli_cmd_flag_none, + "= list driver flags" }, { "logon", wpa_cli_cmd_logon, NULL, cli_cmd_flag_none, "= IEEE 802.1X EAPOL state machine logon" }, @@ -3001,11 +2907,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "scan_results", wpa_cli_cmd_scan_results, NULL, cli_cmd_flag_none, "= get latest scan results" }, + { "abort_scan", wpa_cli_cmd_abort_scan, NULL, + cli_cmd_flag_none, + "= request ongoing scan to be aborted" }, { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss, cli_cmd_flag_none, "<<idx> | <bssid>> = get detailed scan result info" }, - { "get_capability", wpa_cli_cmd_get_capability, NULL, - cli_cmd_flag_none, + { "get_capability", wpa_cli_cmd_get_capability, + wpa_cli_complete_get_capability, cli_cmd_flag_none, "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> " "= get capabilities" }, { "reconfigure", wpa_cli_cmd_reconfigure, NULL, @@ -3017,8 +2926,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "interface_add", wpa_cli_cmd_interface_add, NULL, cli_cmd_flag_none, "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n" - " <bridge_name> = adds new interface, all parameters but <ifname>\n" - " are optional" }, + " <bridge_name> <create> <type> = adds new interface, all " + "parameters but\n" + " <ifname> are optional. Supported types are station ('sta') and " + "AP ('ap')" }, { "interface_remove", wpa_cli_cmd_interface_remove, NULL, cli_cmd_flag_none, "<ifname> = removes the interface" }, @@ -3157,6 +3068,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL, cli_cmd_flag_none, "<ifname> = Remove mesh group interface" }, + { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL, + cli_cmd_flag_none, + "<addr> = Remove a mesh peer" }, + { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL, + cli_cmd_flag_none, + "<addr> [duration=<seconds>] = Add a mesh peer" }, #endif /* CONFIG_MESH */ #ifdef CONFIG_P2P { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, @@ -3180,6 +3097,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { "<ifname> = remove P2P group interface (terminate group if GO)" }, { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none, "[ht40] = add a new P2P group (local end as GO)" }, + { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL, + cli_cmd_flag_none, + "<dev_addr> = Get peer interface address on local GO using peer Device Address" }, { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "<addr> <method> = request provisioning discovery" }, @@ -3248,6 +3168,18 @@ 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" }, + { "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" + VENDOR_ELEM_FRAME_ID }, + { "vendor_elem_get", wpa_cli_cmd_vendor_elem_get, NULL, + cli_cmd_flag_none, + "<frame id> = get vendor specific IE(s) to frame(s)\n" + VENDOR_ELEM_FRAME_ID }, + { "vendor_elem_remove", wpa_cli_cmd_vendor_elem_remove, NULL, + 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, @@ -3336,6 +3268,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "signal_poll", wpa_cli_cmd_signal_poll, NULL, cli_cmd_flag_none, "= get signal parameters" }, + { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL, + cli_cmd_flag_none, + "= set signal monitor parameters" }, { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, cli_cmd_flag_none, "= get TX/RX packet counters" }, @@ -3350,7 +3285,7 @@ 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> = Send BSS Transition Management Query" }, + "<query reason> [list] = Send BSS Transition Management Query" }, #endif /* CONFIG_WNM */ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, "<params..> = Sent unprocessed command" }, @@ -3367,8 +3302,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { }, { "neighbor_rep_request", wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none, - "[ssid=<SSID>] = Trigger request to AP for neighboring AP report " - "(with optional given SSID, default: current SSID)" + "[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)" }, { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none, "= flush ERP keys" }, @@ -3380,6 +3314,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL, cli_cmd_flag_none, "<interface type> = retrieve preferred freq list for the specified interface type" }, + { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL, + cli_cmd_flag_none, + "<freq> <period> <interval> <count> = start P2P listen offload" }, + { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL, + cli_cmd_flag_none, + "= stop P2P listen offload" }, { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; @@ -3578,12 +3518,6 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } -static int str_match(const char *a, const char *b) -{ - return os_strncmp(a, b, os_strlen(b)) == 0; -} - - static int wpa_cli_exec(const char *program, const char *arg1, const char *arg2) { @@ -3591,6 +3525,10 @@ static int wpa_cli_exec(const char *program, const char *arg1, size_t len; int res; + /* If no interface is specified, set the global */ + if (!arg1) + arg1 = "global"; + len = os_strlen(arg1) + os_strlen(arg2) + 2; arg = os_malloc(len); if (arg == NULL) @@ -3635,7 +3573,7 @@ static void wpa_cli_action_process(const char *msg) pos = prev; } - if (str_match(pos, WPA_EVENT_CONNECTED)) { + if (str_starts(pos, WPA_EVENT_CONNECTED)) { int new_id = -1; os_unsetenv("WPA_ID"); os_unsetenv("WPA_ID_STR"); @@ -3671,44 +3609,48 @@ static void wpa_cli_action_process(const char *msg) wpa_cli_last_id = new_id; wpa_cli_exec(action_file, ifname, "CONNECTED"); } - } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) { + } else if (str_starts(pos, WPA_EVENT_DISCONNECTED)) { if (wpa_cli_connected) { wpa_cli_connected = 0; wpa_cli_exec(action_file, ifname, "DISCONNECTED"); } - } else if (str_match(pos, MESH_GROUP_STARTED)) { + } else if (str_starts(pos, AP_EVENT_ENABLED)) { + wpa_cli_exec(action_file, ctrl_ifname, pos); + } else if (str_starts(pos, AP_EVENT_DISABLED)) { + wpa_cli_exec(action_file, ctrl_ifname, pos); + } else if (str_starts(pos, MESH_GROUP_STARTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); - } else if (str_match(pos, MESH_GROUP_REMOVED)) { + } else if (str_starts(pos, MESH_GROUP_REMOVED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); - } else if (str_match(pos, MESH_PEER_CONNECTED)) { + } else if (str_starts(pos, MESH_PEER_CONNECTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); - } else if (str_match(pos, MESH_PEER_DISCONNECTED)) { + } else if (str_starts(pos, MESH_PEER_DISCONNECTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); - } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) { + } else if (str_starts(pos, P2P_EVENT_GROUP_STARTED)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) { + } else if (str_starts(pos, P2P_EVENT_GROUP_REMOVED)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) { + } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) { + } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) { + } else if (str_starts(pos, P2P_EVENT_GO_NEG_FAILURE)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, WPS_EVENT_SUCCESS)) { + } else if (str_starts(pos, WPS_EVENT_SUCCESS)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, WPS_EVENT_FAIL)) { + } else if (str_starts(pos, WPS_EVENT_FAIL)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, AP_STA_CONNECTED)) { + } else if (str_starts(pos, AP_STA_CONNECTED)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, AP_STA_DISCONNECTED)) { + } else if (str_starts(pos, AP_STA_DISCONNECTED)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) { + } else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) { + } else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) { + } else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) { wpa_cli_exec(action_file, ifname, pos); - } else if (str_match(pos, WPA_EVENT_TERMINATING)) { + } else if (str_starts(pos, WPA_EVENT_TERMINATING)) { printf("wpa_supplicant is terminating - stop monitoring\n"); wpa_cli_quit = 1; } @@ -3818,7 +3760,7 @@ static int check_terminating(const char *msg) pos = msg; } - if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) { + if (str_starts(pos, WPA_EVENT_TERMINATING) && ctrl_conn) { edit_clear_line(); printf("\rConnection to wpa_supplicant lost - trying to " "reconnect\n"); @@ -3869,37 +3811,6 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) } } -#define max_args 10 - -static int tokenize_cmd(char *cmd, char *argv[]) -{ - char *pos; - int argc = 0; - - pos = cmd; - for (;;) { - while (*pos == ' ') - pos++; - if (*pos == '\0') - break; - argv[argc] = pos; - argc++; - if (argc == max_args) - break; - if (*pos == '"') { - char *pos2 = os_strrchr(pos, '"'); - if (pos2) - pos = pos2 + 1; - } - while (*pos != '\0' && *pos != ' ') - pos++; - if (*pos == ' ') - *pos++ = '\0'; - } - - return argc; -} - static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx) { @@ -4084,7 +3995,7 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx) if (ctrl_ifname == NULL) ctrl_ifname = wpa_cli_get_default_ifname(); - if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) { + if (wpa_cli_open_connection(ctrl_ifname, 1)) { if (!warning_displayed) { printf("Could not connect to wpa_supplicant: " "%s - re-trying\n", @@ -4309,7 +4220,7 @@ int main(int argc, char *argv[]) interactive = (argc == optind) && (action_file == NULL); if (interactive) - printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license); + printf("%s\n\n%s\n\n", wpa_cli_version, cli_license); if (eloop_init()) return -1; @@ -4373,7 +4284,7 @@ int main(int argc, char *argv[]) } } - if (daemonize && os_daemonize(pid_file)) + if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) return -1; if (action_file) diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c index 850ec40..511df4f 100644 --- a/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant/wpa_priv.c @@ -29,6 +29,8 @@ struct wpa_priv_interface { char *sock_name; int fd; + void *ctx; + const struct wpa_driver_ops *driver; void *drv_priv; void *drv_global_priv; @@ -40,6 +42,10 @@ struct wpa_priv_interface { struct sockaddr_un l2_addr; }; +struct wpa_priv_global { + struct wpa_priv_interface *interfaces; +}; + static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, struct sockaddr_un *from) @@ -65,7 +71,8 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, if (iface->driver->init2) { if (iface->driver->global_init) { - iface->drv_global_priv = iface->driver->global_init(); + iface->drv_global_priv = + iface->driver->global_init(iface->ctx); if (!iface->drv_global_priv) { wpa_printf(MSG_INFO, "Failed to initialize driver global context"); @@ -638,7 +645,7 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) static struct wpa_priv_interface * -wpa_priv_interface_init(const char *dir, const char *params) +wpa_priv_interface_init(void *ctx, const char *dir, const char *params) { struct wpa_priv_interface *iface; char *pos; @@ -654,6 +661,7 @@ wpa_priv_interface_init(const char *dir, const char *params) if (iface == NULL) return NULL; iface->fd = -1; + iface->ctx = ctx; len = pos - params; iface->driver_name = dup_binstr(params, len); @@ -1002,6 +1010,37 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } +void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) +{ + struct wpa_priv_global *global = ctx; + struct wpa_priv_interface *iface; + + if (event != EVENT_INTERFACE_STATUS) + return; + + for (iface = global->interfaces; iface; iface = iface->next) { + if (os_strcmp(iface->ifname, data->interface_status.ifname) == + 0) + break; + } + if (iface && iface->driver->get_ifindex) { + unsigned int ifindex; + + ifindex = iface->driver->get_ifindex(iface->drv_priv); + if (ifindex != data->interface_status.ifindex) { + wpa_printf(MSG_DEBUG, + "%s: interface status ifindex %d mismatch (%d)", + iface->ifname, ifindex, + data->interface_status.ifindex); + return; + } + } + if (iface) + wpa_supplicant_event(iface, event, data); +} + + void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { @@ -1060,7 +1099,7 @@ static void wpa_priv_fd_workaround(void) static void usage(void) { printf("wpa_priv v" VERSION_STR "\n" - "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and " + "Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> and " "contributors\n" "\n" "usage:\n" @@ -1077,13 +1116,17 @@ int main(int argc, char *argv[]) char *pid_file = NULL; int daemonize = 0; char *ctrl_dir = "/var/run/wpa_priv"; - struct wpa_priv_interface *interfaces = NULL, *iface; + struct wpa_priv_global global; + struct wpa_priv_interface *iface; if (os_program_init()) return -1; wpa_priv_fd_workaround(); + os_memset(&global, 0, sizeof(global)); + global.interfaces = NULL; + for (;;) { c = getopt(argc, argv, "Bc:dP:"); if (c < 0) @@ -1121,14 +1164,14 @@ int main(int argc, char *argv[]) for (i = optind; i < argc; i++) { wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]); - iface = wpa_priv_interface_init(ctrl_dir, argv[i]); + iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]); if (iface == NULL) goto out; - iface->next = interfaces; - interfaces = iface; + iface->next = global.interfaces; + global.interfaces = iface; } - if (daemonize && os_daemonize(pid_file)) + if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) goto out; eloop_register_signal_terminate(wpa_priv_terminate, NULL); @@ -1137,7 +1180,7 @@ int main(int argc, char *argv[]) ret = 0; out: - iface = interfaces; + iface = global.interfaces; while (iface) { struct wpa_priv_interface *prev = iface; iface = iface->next; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index ef55fdc..7361ee9 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> + * 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. @@ -11,6 +11,10 @@ */ #include "includes.h" +#ifdef CONFIG_MATCH_IFACE +#include <net/if.h> +#include <fnmatch.h> +#endif /* CONFIG_MATCH_IFACE */ #include "common.h" #include "crypto/random.h" @@ -58,7 +62,7 @@ const char *const wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2016, 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" @@ -188,7 +192,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; const u8 *bssid = wpa_s->bssid; - if (is_zero_ether_addr(bssid)) + if (!is_zero_ether_addr(wpa_s->pending_bssid) && + (wpa_s->wpa_state == WPA_AUTHENTICATING || + wpa_s->wpa_state == WPA_ASSOCIATING)) bssid = wpa_s->pending_bssid; wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.", MAC2STR(bssid)); @@ -397,6 +403,18 @@ void free_hw_features(struct wpa_supplicant *wpa_s) } +static 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) { + dl_list_del(&bss->list); + os_free(bss); + } +} + + static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { int i; @@ -536,6 +554,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->last_scan_res = NULL; #ifdef CONFIG_HS20 + if (wpa_s->drv_priv) + wpa_drv_configure_frame_filters(wpa_s, 0); hs20_deinit(wpa_s); #endif /* CONFIG_HS20 */ @@ -545,6 +565,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) } wmm_ac_notify_disassoc(wpa_s); + + wpa_s->sched_scan_plans_num = 0; + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = NULL; + +#ifdef CONFIG_MBO + wpa_s->non_pref_chan_num = 0; + os_free(wpa_s->non_pref_chan); + wpa_s->non_pref_chan = NULL; +#endif /* CONFIG_MBO */ + + free_bss_tmp_disallowed(wpa_s); + + wpabuf_free(wpa_s->lci); + wpa_s->lci = NULL; } @@ -963,6 +998,11 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx) wpa_supplicant_terminate_proc(global); } } + + if (wpa_debug_reopen_file() < 0) { + /* Ignore errors since we cannot really do much to fix this */ + wpa_printf(MSG_DEBUG, "Could not reopen debug log file"); + } } @@ -1150,6 +1190,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, return -1; } +#ifdef CONFIG_NO_WPA + wpa_s->group_cipher = WPA_CIPHER_NONE; + wpa_s->pairwise_cipher = WPA_CIPHER_NONE; +#else /* CONFIG_NO_WPA */ sel = ie.group_cipher & ssid->group_cipher; wpa_s->group_cipher = wpa_pick_group_cipher(sel); if (wpa_s->group_cipher < 0) { @@ -1169,6 +1213,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s", wpa_cipher_txt(wpa_s->pairwise_cipher)); +#endif /* CONFIG_NO_WPA */ sel = ie.key_mgmt & ssid->key_mgmt; #ifdef CONFIG_SAE @@ -1279,7 +1324,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, int psk_set = 0; if (ssid->psk_set) { - wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, + NULL); psk_set = 1; } #ifndef CONFIG_NO_PBKDF2 @@ -1290,7 +1336,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, 4096, psk, PMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL); psk_set = 1; os_memset(psk, 0, sizeof(psk)); } @@ -1328,7 +1374,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " "external passphrase)", psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, + NULL); psk_set = 1; os_memset(psk, 0, sizeof(psk)); } else @@ -1341,7 +1388,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, ext_password_free(pw); return -1; } - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, + NULL); psk_set = 1; os_memset(psk, 0, sizeof(psk)); } else { @@ -1404,9 +1452,20 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) if (wpa_s->conf->hs20) *pos |= 0x40; /* Bit 46 - WNM-Notification */ #endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + *pos |= 0x40; /* Bit 46 - WNM-Notification */ +#endif /* CONFIG_MBO */ break; case 6: /* Bits 48-55 */ break; + case 7: /* Bits 56-63 */ + break; + case 8: /* Bits 64-71 */ + if (wpa_s->conf->ftm_responder) + *pos |= 0x40; /* Bit 70 - FTM responder */ + if (wpa_s->conf->ftm_initiator) + *pos |= 0x80; /* Bit 71 - FTM initiator */ + break; } } @@ -1416,6 +1475,9 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen) u8 *pos = buf; u8 len = 6, 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) { @@ -1586,6 +1648,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_connect_work *cwork; int rand_style; + wpa_s->own_disconnect_req = 0; + + /* + * If we are starting a new connection, any previously pending EAPOL + * RX cannot be valid anymore. + */ + wpabuf_free(wpa_s->pending_eapol_rx); + wpa_s->pending_eapol_rx = NULL; + if (ssid->mac_addr == -1) rand_style = wpa_s->conf->mac_addr; else @@ -1593,9 +1664,11 @@ 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; if (wpa_s->last_ssid == ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS"); + wpa_s->reassoc_same_ess = 1; if (wpa_s->current_bss && wpa_s->current_bss == bss) { wmm_ac_save_tspecs(wpa_s); wpa_s->reassoc_same_bss = 1; @@ -1661,10 +1734,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } wpa_s->current_bss = bss; - wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED - "ssid=\"%s\" id=%d", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len), - ssid->id); + wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len), + ssid->id); #else /* CONFIG_MESH */ wpa_msg(wpa_s, MSG_ERROR, "mesh mode support not included in the build"); @@ -1694,6 +1766,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + wpas_abort_ongoing_scan(wpa_s); + cwork = os_zalloc(sizeof(*cwork)); if (cwork == NULL) return; @@ -1715,6 +1789,36 @@ static int bss_is_ibss(struct wpa_bss *bss) } +static int drv_supports_vht(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid) +{ + enum hostapd_hw_mode hw_mode; + struct hostapd_hw_modes *mode = NULL; + 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; + for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) { + if (wpa_s->hw.modes[i].mode == hw_mode) { + mode = &wpa_s->hw.modes[i]; + break; + } + } + + if (!mode) + return 0; + + return mode->vht_capab != 0; +} + + void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, struct hostapd_freq_params *freq) @@ -1727,8 +1831,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; u8 channel; int i, chan_idx, ht40 = -1, res, obss_scan = 1; - unsigned int j; + unsigned int j, k; struct hostapd_freq_params vht_freq; + int chwidth, seg0, seg1; + u32 vht_caps = 0; freq->freq = ssid->frequency; @@ -1780,6 +1886,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (!mode) return; +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht) { + freq->ht_enabled = 0; + return; + } +#endif /* CONFIG_HT_OVERRIDES */ + freq->ht_enabled = ht_supported(mode); if (!freq->ht_enabled) return; @@ -1801,6 +1914,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) return; +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht40) + return; +#endif /* CONFIG_HT_OVERRIDES */ + /* Check/setup HT40+/HT40- */ for (j = 0; j < ARRAY_SIZE(ht40plus); j++) { if (ht40plus[j] == channel) { @@ -1825,22 +1943,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, freq->channel = pri_chan->chan; - switch (ht40) { - case -1: + if (ht40 == -1) { if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS)) return; - freq->sec_channel_offset = -1; - break; - case 1: + } else { if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS)) return; - freq->sec_channel_offset = 1; - break; - default: - break; } + freq->sec_channel_offset = ht40; - if (freq->sec_channel_offset && obss_scan) { + if (obss_scan) { struct wpa_scan_results *scan_res; scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); @@ -1878,12 +1990,12 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, "IBSS/mesh: setup freq channel %d, sec_channel_offset %d", freq->channel, freq->sec_channel_offset); - /* Not sure if mesh is ready for VHT */ - if (ssid->mode != WPAS_MODE_IBSS) + if (!drv_supports_vht(wpa_s, ssid)) return; /* For IBSS check VHT_IBSS flag */ - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) + if (ssid->mode == WPAS_MODE_IBSS && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) return; vht_freq = *freq; @@ -1914,12 +2026,55 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, return; } + chwidth = VHT_CHANWIDTH_80MHZ; + seg0 = vht80[j] + 6; + seg1 = 0; + + if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) { + /* setup center_freq2, bandwidth */ + for (k = 0; k < ARRAY_SIZE(vht80); k++) { + /* Only accept 80 MHz segments separated by a gap */ + if (j == k || abs(vht80[j] - vht80[k]) == 16) + continue; + for (i = vht80[k]; i < vht80[k] + 16; i += 4) { + struct hostapd_channel_data *chan; + + chan = hw_get_channel_chan(mode, i, NULL); + if (!chan) + continue; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_NO_IR | + HOSTAPD_CHAN_RADAR)) + continue; + + /* Found a suitable second segment for 80+80 */ + chwidth = VHT_CHANWIDTH_80P80MHZ; + vht_caps |= + VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + seg1 = vht80[k] + 6; + } + + if (chwidth == VHT_CHANWIDTH_80P80MHZ) + break; + } + } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) { + if (freq->freq == 5180) { + chwidth = VHT_CHANWIDTH_160MHZ; + vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + seg0 = 50; + } else if (freq->freq == 5520) { + chwidth = VHT_CHANWIDTH_160MHZ; + vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + seg0 = 114; + } + } + if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq, freq->channel, freq->ht_enabled, vht_freq.vht_enabled, freq->sec_channel_offset, - VHT_CHANWIDTH_80MHZ, - vht80[j] + 6, 0, 0) != 0) + chwidth, seg0, seg1, vht_caps) != 0) return; *freq = vht_freq; @@ -1944,6 +2099,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) 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; @@ -1952,6 +2108,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) 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 */ if (deinit) { if (work->started) { @@ -1974,6 +2133,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) 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; @@ -2015,7 +2175,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } else { wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + 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); @@ -2136,25 +2299,21 @@ 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_HS20 - if (is_hs20_network(wpa_s, ssid, bss)) { - struct wpabuf *hs20; - hs20 = wpabuf_alloc(20); - 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; - if (wpabuf_len(hs20) <= len) { - os_memcpy(wpa_ie + wpa_ie_len, - wpabuf_head(hs20), wpabuf_len(hs20)); - wpa_ie_len += wpabuf_len(hs20); - } - wpabuf_free(hs20); +#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; } } -#endif /* CONFIG_HS20 */ +#endif /* CONFIG_MBO */ /* * Workaround: Add Extended Capabilities element only if the AP @@ -2164,6 +2323,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) * element in all cases, it is justifiable to skip it to avoid * interoperability issues. */ + if (ssid->p2p_group) + wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); + else + wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); + if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) { u8 ext_capab[18]; int ext_capab_len; @@ -2180,6 +2344,29 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } } +#ifdef CONFIG_HS20 + if (is_hs20_network(wpa_s, ssid, bss)) { + struct wpabuf *hs20; + + hs20 = wpabuf_alloc(20); + 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; + if (wpabuf_len(hs20) <= len) { + os_memcpy(wpa_ie + wpa_ie_len, + wpabuf_head(hs20), wpabuf_len(hs20)); + wpa_ie_len += wpabuf_len(hs20); + } + wpabuf_free(hs20); + + hs20_configure_frame_filters(wpa_s); + } + } +#endif /* CONFIG_HS20 */ + if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) { struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]; size_t len; @@ -2204,6 +2391,17 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } #endif /* CONFIG_FST */ +#ifdef CONFIG_MBO + if (mbo) { + int len; + + len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len, + sizeof(wpa_ie) - wpa_ie_len); + if (len >= 0) + wpa_ie_len += len; + } +#endif /* CONFIG_MBO */ + wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); use_crypt = 1; cipher_pairwise = wpa_s->pairwise_cipher; @@ -2256,9 +2454,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } params.bssid_hint = bss->bssid; params.freq_hint = bss->freq; + params.pbss = bss_is_pbss(bss); } else { params.ssid = ssid->ssid; params.ssid_len = ssid->ssid_len; + params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0; } if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set && @@ -2342,8 +2542,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.p2p = ssid->p2p_group; - if (wpa_s->parent->set_sta_uapsd) - params.uapsd = wpa_s->parent->sta_uapsd; + if (wpa_s->p2pdev->set_sta_uapsd) + params.uapsd = wpa_s->p2pdev->sta_uapsd; else params.uapsd = -1; @@ -2384,6 +2584,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } #endif /* CONFIG_P2P */ + if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) && + wpa_s->current_ssid) + params.prev_bssid = prev_bssid; + ret = wpa_drv_associate(wpa_s, ¶ms); if (ret < 0) { wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " @@ -2451,8 +2655,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; - if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) + + if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) { wpa_s->current_bss = bss; +#ifdef CONFIG_HS20 + hs20_configure_frame_filters(wpa_s); +#endif /* CONFIG_HS20 */ + } + 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) @@ -2497,12 +2707,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state)); - if (!is_zero_ether_addr(wpa_s->bssid)) - addr = wpa_s->bssid; - else if (!is_zero_ether_addr(wpa_s->pending_bssid) && - (wpa_s->wpa_state == WPA_AUTHENTICATING || - wpa_s->wpa_state == WPA_ASSOCIATING)) + if (!is_zero_ether_addr(wpa_s->pending_bssid) && + (wpa_s->wpa_state == WPA_AUTHENTICATING || + wpa_s->wpa_state == WPA_ASSOCIATING)) addr = wpa_s->pending_bssid; + else if (!is_zero_ether_addr(wpa_s->bssid)) + addr = wpa_s->bssid; else if (wpa_s->wpa_state == WPA_ASSOCIATING) { /* * When using driver-based BSS selection, we may not know the @@ -2520,8 +2730,8 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MESH if (wpa_s->ifmsh) { - wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s", - wpa_s->ifname); + wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s", + wpa_s->ifname); wpa_supplicant_leave_mesh(wpa_s); } #endif /* CONFIG_MESH */ @@ -2559,6 +2769,95 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, /** + * wpa_supplicant_add_network - Add a new network + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: The new network configuration or %NULL if operation failed + * + * This function performs the following operations: + * 1. Adds a new network. + * 2. Send network addition notification. + * 3. Marks the network disabled. + * 4. Set network default parameters. + */ +struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid; + + ssid = wpa_config_add_network(wpa_s->conf); + if (!ssid) + return NULL; + wpas_notify_network_added(wpa_s, ssid); + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + return ssid; +} + + +/** + * wpa_supplicant_remove_network - Remove a configured network based on id + * @wpa_s: wpa_supplicant structure for a network interface + * @id: Unique network id to search for + * Returns: 0 on success, or -1 if the network was not found, -2 if the network + * could not be removed + * + * This function performs the following operations: + * 1. Removes the network. + * 2. Send network removal notification. + * 3. Update internal state machines. + * 4. Stop any running sched scans. + */ +int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) +{ + struct wpa_ssid *ssid; + int was_disabled; + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (!ssid) + return -1; + wpas_notify_network_removed(wpa_s, ssid); + + if (wpa_s->last_ssid == ssid) + wpa_s->last_ssid = NULL; + + if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) { +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + /* + * Invalidate the EAP session cache if the current or + * previously used network is removed. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + + if (ssid == wpa_s->current_ssid) { + wpa_sm_set_config(wpa_s->wpa, NULL); + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + + if (wpa_s->wpa_state >= WPA_AUTHENTICATING) + wpa_s->own_disconnect_req = 1; + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + } + + was_disabled = ssid->disabled; + + if (wpa_config_remove_network(wpa_s->conf, id) < 0) + return -2; + + if (!was_disabled && wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, + "Stop ongoing sched_scan to remove network from filters"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + + return 0; +} + + +/** * wpa_supplicant_enable_network - Mark a configured network as enabled * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network or %NULL @@ -2688,7 +2987,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpas_notify_network_enabled_changed(wpa_s, other_ssid); } - if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) { + if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid && + wpa_s->wpa_state >= WPA_AUTHENTICATING) { /* We are already associated with the selected network */ wpa_printf(MSG_DEBUG, "Already associated with the " "selected network - do nothing"); @@ -2717,6 +3017,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, if (wpa_s->connect_without_scan || wpa_supplicant_fast_associate(wpa_s) != 1) { wpa_s->scan_req = NORMAL_SCAN_REQ; + wpas_scan_reset_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0); } @@ -2994,7 +3295,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i) struct wpa_global *global = wpa_s->global; if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) { - global->drv_priv[i] = wpa_drivers[i]->global_init(); + global->drv_priv[i] = wpa_drivers[i]->global_init(global); if (global->drv_priv[i] == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize driver " "'%s'", wpa_drivers[i]->name); @@ -3077,6 +3378,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_auth_resp) { + wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!"); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + #ifdef CONFIG_PEERKEY if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid && wpa_s->current_ssid->peerkey && @@ -3361,8 +3669,11 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) wpa_s->scan_interval = 5; wpa_s->new_connection = 1; wpa_s->parent = parent ? parent : wpa_s; + wpa_s->p2pdev = wpa_s->parent; wpa_s->sched_scanning = 0; + dl_list_init(&wpa_s->bss_tmp_disallowed); + return wpa_s; } @@ -3614,8 +3925,8 @@ void wpa_supplicant_apply_vht_overrides( if (!vhtcaps || !vhtcaps_mask) return; - vhtcaps->vht_capabilities_info = ssid->vht_capa; - vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask; + vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa); + vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask); #ifdef CONFIG_HT_OVERRIDES /* if max ampdu is <= 3, we have to make the HT cap the same */ @@ -3637,15 +3948,17 @@ void wpa_supplicant_apply_vht_overrides( #define OVERRIDE_MCS(i) \ if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \ vhtcaps_mask->vht_supported_mcs_set.tx_map |= \ - 3 << 2 * (i - 1); \ + host_to_le16(3 << 2 * (i - 1)); \ vhtcaps->vht_supported_mcs_set.tx_map |= \ - ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \ + host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \ + 2 * (i - 1)); \ } \ if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \ vhtcaps_mask->vht_supported_mcs_set.rx_map |= \ - 3 << 2 * (i - 1); \ + host_to_le16(3 << 2 * (i - 1)); \ vhtcaps->vht_supported_mcs_set.rx_map |= \ - ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \ + host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \ + 2 * (i - 1)); \ } OVERRIDE_MCS(1); @@ -3817,8 +4130,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr, } -const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx, - Boolean mb_only) +static const u8 * wpas_fst_get_peer_first(void *ctx, + struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) { struct wpa_supplicant *wpa_s = ctx; @@ -3830,8 +4144,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx, } -const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx, - Boolean mb_only) +static const u8 * wpas_fst_get_peer_next(void *ctx, + struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) { return NULL; } @@ -3870,6 +4185,55 @@ static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s, } +enum wpa_radio_work_band wpas_freq_to_band(int freq) +{ + if (freq < 3000) + return BAND_2_4_GHZ; + if (freq > 50000) + return BAND_60_GHZ; + return BAND_5_GHZ; +} + + +unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs) +{ + int i; + unsigned int band = 0; + + if (freqs) { + /* freqs are specified for the radio work */ + for (i = 0; freqs[i]; i++) + band |= wpas_freq_to_band(freqs[i]); + } else { + /* + * freqs are not specified, implies all + * the supported freqs by HW + */ + for (i = 0; i < wpa_s->hw.num_modes; i++) { + if (wpa_s->hw.modes[i].num_channels != 0) { + if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211B || + wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211G) + band |= BAND_2_4_GHZ; + else if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211A) + band |= BAND_5_GHZ; + else if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211AD) + band |= BAND_60_GHZ; + else if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211ANY) + band = BAND_2_4_GHZ | BAND_5_GHZ | + BAND_60_GHZ; + } + } + } + + return band; +} + + static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s, const char *rn) { @@ -3922,11 +4286,103 @@ static void radio_work_free(struct wpa_radio_work *work) } #endif /* CONFIG_P2P */ + 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", + work->type, work, + work->wpa_s->radio->num_active_works); + } + dl_list_del(&work->list); os_free(work); } +static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio) +{ + struct wpa_radio_work *active_work = NULL; + struct wpa_radio_work *tmp; + + /* Get the active work to know the type and band. */ + dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) { + if (tmp->started) { + active_work = tmp; + break; + } + } + + if (!active_work) { + /* No active work, start one */ + radio->num_active_works = 0; + dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, + list) { + if (os_strcmp(tmp->type, "scan") == 0 && + radio->external_scan_running && + (((struct wpa_driver_scan_params *) + tmp->ctx)->only_new_results || + tmp->wpa_s->clear_driver_scan_cache)) + continue; + return tmp; + } + return NULL; + } + + if (os_strcmp(active_work->type, "sme-connect") == 0 || + os_strcmp(active_work->type, "connect") == 0) { + /* + * If the active work is either connect or sme-connect, + * do not parallelize them with other radio works. + */ + wpa_dbg(active_work->wpa_s, MSG_DEBUG, + "Do not parallelize radio work with %s", + active_work->type); + return NULL; + } + + dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) { + if (tmp->started) + continue; + + /* + * 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) + break; + + /* + * Check that the radio works are distinct and + * on different bands. + */ + if (os_strcmp(active_work->type, tmp->type) != 0 && + (active_work->bands != tmp->bands)) { + /* + * If a scan has to be scheduled through nl80211 scan + * interface and if an external scan is already running, + * do not schedule the scan since it is likely to get + * rejected by kernel. + */ + if (os_strcmp(tmp->type, "scan") == 0 && + radio->external_scan_running && + (((struct wpa_driver_scan_params *) + tmp->ctx)->only_new_results || + tmp->wpa_s->clear_driver_scan_cache)) + continue; + + wpa_dbg(active_work->wpa_s, MSG_DEBUG, + "active_work:%s new_work:%s", + active_work->type, tmp->type); + return tmp; + } + } + + /* Did not find a radio work to schedule in parallel. */ + return NULL; +} + + static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) { struct wpa_radio *radio = eloop_ctx; @@ -3935,26 +4391,48 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) struct wpa_supplicant *wpa_s; work = dl_list_first(&radio->work, struct wpa_radio_work, list); - if (work == NULL) + if (work == NULL) { + radio->num_active_works = 0; return; - - if (work->started) - return; /* already started and still in progress */ + } wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant, radio_list); - if (wpa_s && wpa_s->radio->external_scan_running) { - wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); - return; + + if (!(wpa_s && + wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) { + if (work->started) + return; /* already started and still in progress */ + + if (wpa_s && wpa_s->radio->external_scan_running) { + wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); + return; + } + } else { + work = NULL; + if (radio->num_active_works < MAX_ACTIVE_WORKS) { + /* get the work to schedule next */ + work = radio_work_get_next_work(radio); + } + if (!work) + return; } + wpa_s = work->wpa_s; os_get_reltime(&now); os_reltime_sub(&now, &work->time, &diff); - wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait", + wpa_dbg(wpa_s, MSG_DEBUG, + "Starting radio work '%s'@%p after %ld.%06ld second wait", work->type, work, diff.sec, diff.usec); work->started = 1; work->time = now; + radio->num_active_works++; + work->cb(work, 0); + + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) && + radio->num_active_works < MAX_ACTIVE_WORKS) + radio_work_check_next(wpa_s); } @@ -4062,6 +4540,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, void (*cb)(struct wpa_radio_work *work, int deinit), void *ctx) { + struct wpa_radio *radio = wpa_s->radio; struct wpa_radio_work *work; int was_empty; @@ -4076,6 +4555,16 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, work->cb = cb; work->ctx = ctx; + if (freq) + work->bands = wpas_freq_to_band(freq); + else if (os_strcmp(type, "scan") == 0 || + os_strcmp(type, "p2p-scan") == 0) + work->bands = wpas_get_bands(wpa_s, + ((struct wpa_driver_scan_params *) + ctx)->freqs); + else + work->bands = wpas_get_bands(wpa_s, NULL); + was_empty = dl_list_empty(&wpa_s->radio->work); if (next) dl_list_add(&wpa_s->radio->work, &work->list); @@ -4084,6 +4573,12 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, if (was_empty) { wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately"); radio_work_check_next(wpa_s); + } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) + && radio->num_active_works < MAX_ACTIVE_WORKS) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Try to schedule a radio work (num_active_works=%u)", + radio->num_active_works); + radio_work_check_next(wpa_s); } return 0; @@ -4339,6 +4834,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->probe_resp_offloads = capa.probe_resp_offloads; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; + wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans; + wpa_s->max_sched_scan_plan_interval = + capa.max_sched_scan_plan_interval; + wpa_s->max_sched_scan_plan_iterations = + capa.max_sched_scan_plan_iterations; wpa_s->sched_scan_supported = capa.sched_scan_supported; wpa_s->max_match_sets = capa.max_match_sets; wpa_s->max_remain_on_chan = capa.max_remain_on_chan; @@ -4478,6 +4978,17 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpas_rrm_reset(wpa_s); + wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans); + +#ifdef CONFIG_HS20 + hs20_init(wpa_s); +#endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan); +#endif /* CONFIG_MBO */ + + wpa_supplicant_set_default_scan_ies(wpa_s); + return 0; } @@ -4493,6 +5004,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, iface = global->ifaces; while (iface) { + if (iface->p2pdev == wpa_s) + iface->p2pdev = iface->parent; if (iface == wpa_s || iface->parent != wpa_s) { iface = iface->next; continue; @@ -4563,6 +5076,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_MATCH_IFACE + +/** + * wpa_supplicant_match_iface - Match an interface description to a name + * @global: Pointer to global data from wpa_supplicant_init() + * @ifname: Name of the interface to match + * Returns: Pointer to the created interface description or %NULL on failure + */ +struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global, + const char *ifname) +{ + int i; + struct wpa_interface *iface, *miface; + + for (i = 0; i < global->params.match_iface_count; i++) { + miface = &global->params.match_ifaces[i]; + if (!miface->ifname || + fnmatch(miface->ifname, ifname, 0) == 0) { + iface = os_zalloc(sizeof(*iface)); + if (!iface) + return NULL; + *iface = *miface; + iface->ifname = ifname; + return iface; + } + } + + return NULL; +} + + +/** + * wpa_supplicant_match_existing - Match existing interfaces + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: 0 on success, -1 on failure + */ +static int wpa_supplicant_match_existing(struct wpa_global *global) +{ + struct if_nameindex *ifi, *ifp; + struct wpa_supplicant *wpa_s; + struct wpa_interface *iface; + + ifp = if_nameindex(); + if (!ifp) { + wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno)); + return -1; + } + + for (ifi = ifp; ifi->if_name; ifi++) { + wpa_s = wpa_supplicant_get_iface(global, ifi->if_name); + if (wpa_s) + continue; + iface = wpa_supplicant_match_iface(global, ifi->if_name); + if (iface) { + wpa_s = wpa_supplicant_add_iface(global, iface, NULL); + os_free(iface); + if (wpa_s) + wpa_s->matched = 1; + } + } + + if_freenameindex(ifp); + return 0; +} + +#endif /* CONFIG_MATCH_IFACE */ + + /** * wpa_supplicant_add_iface - Add a new network interface * @global: Pointer to global data from wpa_supplicant_init() @@ -4864,6 +5445,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) if (params->override_ctrl_interface) global->params.override_ctrl_interface = os_strdup(params->override_ctrl_interface); +#ifdef CONFIG_MATCH_IFACE + global->params.match_iface_count = params->match_iface_count; + if (params->match_iface_count) { + global->params.match_ifaces = + os_calloc(params->match_iface_count, + sizeof(struct wpa_interface)); + os_memcpy(global->params.match_ifaces, + params->match_ifaces, + params->match_iface_count * + sizeof(struct wpa_interface)); + } +#endif /* CONFIG_MATCH_IFACE */ #ifdef CONFIG_P2P if (params->conf_p2p_dev) global->params.conf_p2p_dev = @@ -4939,12 +5532,18 @@ int wpa_supplicant_run(struct wpa_global *global) struct wpa_supplicant *wpa_s; if (global->params.daemonize && - wpa_supplicant_daemon(global->params.pid_file)) + (wpa_supplicant_daemon(global->params.pid_file) || + eloop_sock_requeue())) + return -1; + +#ifdef CONFIG_MATCH_IFACE + if (wpa_supplicant_match_existing(global)) return -1; +#endif if (global->params.wait_for_monitor) { for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) - if (wpa_s->ctrl_iface) + if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt) wpa_supplicant_ctrl_iface_wait( wpa_s->ctrl_iface); } @@ -5010,6 +5609,9 @@ void wpa_supplicant_deinit(struct wpa_global *global) os_free(global->params.ctrl_interface_group); os_free(global->params.override_driver); os_free(global->params.override_ctrl_interface); +#ifdef CONFIG_MATCH_IFACE + os_free(global->params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ #ifdef CONFIG_P2P os_free(global->params.conf_p2p_dev); #endif /* CONFIG_P2P */ @@ -5042,6 +5644,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s) if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND) wpas_init_ext_pw(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); + #ifdef CONFIG_WPS wpas_wps_update_config(wpa_s); #endif /* CONFIG_WPS */ @@ -5281,6 +5886,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning) wpa_supplicant_req_scan(wpa_s, 0, 0); break; + case WPA_CTRL_REQ_EXT_CERT_CHECK: + if (eap->pending_ext_cert_check != PENDING_CHECK) + return -1; + if (os_strcmp(value, "good") == 0) + eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD; + else if (os_strcmp(value, "bad") == 0) + eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD; + else + return -1; + break; default: wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field); return -1; @@ -5350,6 +5965,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) return NO_MGMT_FRAME_PROTECTION; } + if (ssid && + (ssid->key_mgmt & + ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS | + WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) { + /* + * Do not use the default PMF value for non-RSN networks + * since PMF is available only with RSN and pmf=2 + * configuration would otherwise prevent connections to + * all open networks. + */ + return NO_MGMT_FRAME_PROTECTION; + } + return wpa_s->conf->pmf; } @@ -5508,6 +6136,27 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s) } +/** + * wpas_request_disconnection - Request disconnection + * @wpa_s: Pointer to the network interface + * + * This function is used to request disconnection from the currently connected + * network. This will stop any ongoing scans and initiate deauthentication. + */ +void wpas_request_disconnection(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + wpa_s->reassociate = 0; + wpa_s->disconnected = 1; + wpa_supplicant_cancel_sched_scan(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); +} + + void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title, struct wpa_used_freq_data *freqs_data, unsigned int len) @@ -5690,11 +6339,19 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, #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 @@ -5708,7 +6365,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, * Request must contain a callback function. */ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, + const struct wpa_ssid_value *ssid, + int lci, int civic, void (*cb)(void *ctx, struct wpabuf *neighbor_rep), void *cb_ctx) @@ -5749,7 +6407,9 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, } /* 3 = action category + action code + dialog token */ - buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0)); + 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"); @@ -5769,6 +6429,72 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, 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, @@ -5791,6 +6517,147 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, } +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, @@ -5868,3 +6735,175 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, } wpabuf_free(buf); } + + +struct wpa_supplicant * +wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame) +{ + switch (frame) { +#ifdef CONFIG_P2P + case VENDOR_ELEM_PROBE_REQ_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P_GO: + case VENDOR_ELEM_BEACON_P2P_GO: + case VENDOR_ELEM_P2P_PD_REQ: + case VENDOR_ELEM_P2P_PD_RESP: + case VENDOR_ELEM_P2P_GO_NEG_REQ: + case VENDOR_ELEM_P2P_GO_NEG_RESP: + case VENDOR_ELEM_P2P_GO_NEG_CONF: + case VENDOR_ELEM_P2P_INV_REQ: + case VENDOR_ELEM_P2P_INV_RESP: + case VENDOR_ELEM_P2P_ASSOC_REQ: + case VENDOR_ELEM_P2P_ASSOC_RESP: + return wpa_s->p2pdev; +#endif /* CONFIG_P2P */ + default: + return wpa_s; + } +} + + +void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s) +{ + unsigned int i; + char buf[30]; + + wpa_printf(MSG_DEBUG, "Update vendor elements"); + + for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { + if (wpa_s->vendor_elem[i]) { + int res; + + res = os_snprintf(buf, sizeof(buf), "frame[%u]", i); + if (!os_snprintf_error(sizeof(buf), res)) { + wpa_hexdump_buf(MSG_DEBUG, buf, + wpa_s->vendor_elem[i]); + } + } + } + +#ifdef CONFIG_P2P + if (wpa_s->parent == wpa_s && + wpa_s->global->p2p && + !wpa_s->global->p2p_disabled) + p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); +#endif /* CONFIG_P2P */ +} + + +int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, + const u8 *elem, size_t len) +{ + u8 *ie, *end; + + ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); + end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); + + for (; ie + 1 < end; ie += 2 + ie[1]) { + if (ie + len > end) + break; + if (os_memcmp(ie, elem, len) != 0) + continue; + + if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { + wpabuf_free(wpa_s->vendor_elem[frame]); + wpa_s->vendor_elem[frame] = NULL; + } else { + os_memmove(ie, ie + len, end - (ie + len)); + wpa_s->vendor_elem[frame]->used -= len; + } + wpas_vendor_elem_update(wpa_s); + return 0; + } + + return -1; +} + + +struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, + u16 num_modes, enum hostapd_hw_mode mode) +{ + u16 i; + + for (i = 0; i < num_modes; i++) { + if (modes[i].mode == mode) + return &modes[i]; + } + + return NULL; +} + + +static struct +wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + struct wpa_bss_tmp_disallowed *bss; + + dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0) + return bss; + } + + return NULL; +} + + +void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, + unsigned int sec) +{ + 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; + } + + bss = os_malloc(sizeof(*bss)); + if (!bss) { + wpa_printf(MSG_DEBUG, + "Failed to allocate memory for temp disallow BSS"); + return; + } + + bss->disallowed_until = until; + os_memcpy(bss->bssid, bssid, ETH_ALEN); + dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list); +} + + +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev; + struct os_reltime now, age; + + os_get_reltime(&now); + + 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; + break; + } + } + if (!bss) + 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/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 6fe67e4..b3138e3 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -118,6 +118,25 @@ eapol_version=1 # networks are found, a new IBSS or AP mode network is created. ap_scan=1 +# Whether to force passive scan for network connection +# +# By default, scans will send out Probe Request frames on channels that allow +# active scanning. This advertise the local station to the world. Normally this +# is fine, but users may wish to do passive scanning where the radio should only +# listen quietly for Beacon frames and not send any Probe Request frames. Actual +# functionality may be driver dependent. +# +# This parameter can be used to force only passive scanning to be used +# for network connection cases. It should be noted that this will slow +# down scan operations and reduce likelihood of finding the AP. In +# addition, some use cases will override this due to functional +# requirements, e.g., for finding an AP that uses hidden SSID +# (scan_ssid=1) or P2P device discovery. +# +# 0: Do normal scans (allow active scans) (default) +# 1: Do passive scans. +#passive_scan=0 + # MPM residency # By default, wpa_supplicant implements the mesh peering manager (MPM) for an # open mesh. However, if the driver can implement the MPM, you may set this to @@ -149,10 +168,13 @@ ap_scan=1 fast_reauth=1 # OpenSSL Engine support -# These options can be used to load OpenSSL engines. +# These options can be used to load OpenSSL engines in special or legacy +# modes. # The two engines that are supported currently are shown below: # They are both from the opensc project (http://www.opensc.org/) -# By default no engines are loaded. +# By default the PKCS#11 engine is loaded if the client_cert or +# private_key option appear to be a PKCS#11 URI, and these options +# should not need to be used explicitly. # make the opensc engine available #opensc_engine_path=/usr/lib/opensc/engine_opensc.so # make the pkcs11 engine available @@ -178,7 +200,7 @@ fast_reauth=1 #load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so # Driver interface parameters -# This field can be used to configure arbitrary driver interace parameters. The +# This field can be used to configure arbitrary driver interface parameters. The # format is specific to the selected driver interface. This field is not used # in most cases. #driver_param="field=value" @@ -295,7 +317,9 @@ fast_reauth=1 # up to the limit of 300 seconds (3, 9, 27 ... 300) # For periodic module, parameters would be <fixed interval> #autoscan=periodic:30 -# So a delay of 30 seconds will be applied between each scan +# So a delay of 30 seconds will be applied between each scan. +# Note: If sched_scan_plans are configured and supported by the driver, +# autoscan is ignored. # filter_ssids - SSID-based scan result filtering # 0 = do not filter scan results (default) @@ -339,10 +363,12 @@ fast_reauth=1 # Protected Management Frames default # This parameter can be used to set the default behavior for the ieee80211w -# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2 -# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF -# is enabled/required by default, but can be disabled with the per-network -# ieee80211w parameter. +# parameter for RSN networks. By default, PMF is disabled unless enabled with +# the global pmf=1/2 parameter or with the per-network ieee80211w=1/2 parameter. +# With pmf=1/2, PMF is enabled/required by default, but can be disabled with the +# per-network ieee80211w parameter. This global default value does not apply +# for non-RSN networks (key_mgmt=NONE) since PMF is available only when using +# RSN. #pmf=0 # Enabled SAE finite cyclic groups in preference order @@ -417,6 +443,28 @@ fast_reauth=1 # matching network block #auto_interworking=0 +# GAS Address3 field behavior +# 0 = P2P specification (Address3 = AP BSSID); default +# 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when +# sent to not-associated AP; if associated, AP BSSID) +#gas_address3=0 + +# Publish fine timing measurement (FTM) responder functionality in +# the Extended Capabilities element bit 70. +# Controls whether FTM responder functionality will be published by AP/STA. +# Note that actual FTM responder operation is managed outside wpa_supplicant. +# 0 = Do not publish; default +# 1 = Publish +#ftm_responder=0 + +# Publish fine timing measurement (FTM) initiator functionality in +# the Extended Capabilities element bit 71. +# Controls whether FTM initiator functionality will be published by AP/STA. +# Note that actual FTM initiator operation is managed outside wpa_supplicant. +# 0 = Do not publish; default +# 1 = Publish +#ftm_initiator=0 + # credential block # # Each credential used for automatic network selection is configured as a set @@ -451,6 +499,10 @@ fast_reauth=1 # (EAP-TLS). Full path to the file should be used since working # directory may change when wpa_supplicant is run in the background. # +# Certificates from PKCS#11 tokens can be referenced by a PKCS#11 URI. +# +# For example: private_key="pkcs11:manufacturer=piv_II;id=%01" +# # Alternatively, a named configuration blob can be used by setting # this to blob://blob_name. # @@ -461,6 +513,9 @@ fast_reauth=1 # used since working directory may change when wpa_supplicant is run # in the background. # +# Keys in PKCS#11 tokens can be referenced by a PKCS#11 URI. +# For example: private_key="pkcs11:manufacturer=piv_II;id=%01" +# # Windows certificate store can be used by leaving client_cert out and # configuring private_key in one of the following formats: # @@ -565,6 +620,8 @@ fast_reauth=1 # 0 = do not use OCSP stapling (TLS certificate status extension) # 1 = try to use OCSP stapling, but not require response # 2 = require valid OCSP stapling response +# 3 = require valid OCSP stapling response for all not-trusted +# certificates in the server certificate chain # # sim_num: Identifier for which SIM to use in multi-SIM devices # @@ -597,6 +654,41 @@ fast_reauth=1 # Hotspot 2.0 # hs20=1 +# Scheduled scan plans +# +# A space delimited list of scan plans. Each scan plan specifies the scan +# interval and number of iterations, delimited by a colon. The last scan plan +# will run infinitely and thus must specify only the interval and not the number +# of iterations. +# +# The driver advertises the maximum number of scan plans supported. If more scan +# plans than supported are configured, only the first ones are set (up to the +# maximum supported). The last scan plan that specifies only the interval is +# always set as the last plan. +# +# If the scan interval or the number of iterations for a scan plan exceeds the +# maximum supported, it will be set to the maximum supported value. +# +# Format: +# sched_scan_plans=<interval:iterations> <interval:iterations> ... <interval> +# +# Example: +# sched_scan_plans=10:100 20:200 30 + +# Multi Band Operation (MBO) non-preferred channels +# A space delimited list of non-preferred channels where each channel is a colon +# delimited list of values. +# 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" + +# MBO Cellular Data Capabilities +# 1 = Cellular data connection available +# 2 = Cellular data connection not available +# 3 = Not cellular capable (default) +#mbo_cell_capa=3 + # network block # # Each network (usually AP's sharing the same SSID) is configured as a separate @@ -658,6 +750,17 @@ fast_reauth=1 # an IBSS network with the configured SSID is already present, the frequency of # the network will be used instead of this configured value. # +# pbss: Whether to use PBSS. Relevant to IEEE 802.11ad networks only. +# 0 = do not use PBSS +# 1 = use PBSS +# 2 = don't care (not allowed in AP mode) +# Used together with mode configuration. When mode is AP, it means to start a +# PCP instead of a regular AP. When mode is infrastructure it means connect +# to a PCP instead of AP. In this mode you can also specify 2 (don't care) +# which means connect to either PCP or AP. +# P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in IEEE 802.11ad network. +# For more details, see IEEE Std 802.11ad-2012. +# # scan_freq: List of frequencies to scan # Space-separated list of frequencies in MHz to scan when searching for this # BSS. If the subset of channels used by the network is known, this option can @@ -706,8 +809,19 @@ fast_reauth=1 # IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically # generated WEP keys # NONE = WPA is not used; plaintext or static WEP could be used +# WPA-NONE = WPA-None for IBSS (deprecated; use proto=RSN key_mgmt=WPA-PSK +# instead) +# FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key +# FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication # 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 +# 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 # If not set, this defaults to: WPA-PSK WPA-EAP # # ieee80211w: whether management frame protection is enabled @@ -798,9 +912,13 @@ fast_reauth=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. +# # Following fields are only used with internal EAP implementation. # eap: space-separated list of accepted EAP methods -# MD5 = EAP-MD5 (unsecure and does not generate keying material -> +# MD5 = EAP-MD5 (insecure and does not generate keying material -> # cannot be used with WPA; to be used as a Phase 2 method # with EAP-PEAP or EAP-TTLS) # MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used @@ -891,23 +1009,23 @@ fast_reauth=1 # automatically converted into DH params. # subject_match: Substring to be matched against the subject of the # authentication server certificate. If this string is set, the server -# sertificate is only accepted if it contains this string in the subject. +# certificate is only accepted if it contains this string in the subject. # The subject string is in following format: # /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com -# Note: Since this is a substring match, this cannot be used securily to +# Note: Since this is a substring match, this cannot be used securely to # do a suffix match against a possible domain name in the CN entry. For # such a use case, domain_suffix_match or domain_match should be used # instead. # altsubject_match: Semicolon separated string of entries to be matched against # the alternative subject name of the authentication server certificate. -# If this string is set, the server sertificate is only accepted if it +# If this string is set, the server certificate is only accepted if it # contains one of the entries in an alternative subject name extension. # altSubjectName string is in following format: TYPE:VALUE # Example: EMAIL:server@example.com # Example: DNS:server.example.com;DNS:server2.example.com # Following types are supported: EMAIL, DNS, URI # domain_suffix_match: Constraint for server domain name. If set, this FQDN is -# used as a suffix match requirement for the AAAserver certificate in +# used as a suffix match requirement for the AAA server certificate in # SubjectAltName dNSName element(s). If a matching dNSName is found, this # constraint is met. If no dNSName values are present, this constraint is # matched against SubjectName CN using same suffix match comparison. @@ -995,6 +1113,12 @@ fast_reauth=1 # that have issues interoperating with updated TLS version) # tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers # that have issues interoperating with updated TLS version) +# 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. # # Following certificate/private key fields are used in inner Phase2 # authentication when using EAP-TTLS or EAP-PEAP. @@ -1026,6 +1150,8 @@ fast_reauth=1 # 0 = do not use OCSP stapling (TLS certificate status extension) # 1 = try to use OCSP stapling, but not require response # 2 = require valid OCSP stapling response +# 3 = require valid OCSP stapling response for all not-trusted +# certificates in the server certificate chain # # openssl_ciphers: OpenSSL specific cipher configuration # This can be used to override the global openssl_ciphers configuration @@ -1059,6 +1185,9 @@ fast_reauth=1 # number of authentication servers. Strict EAP conformance mode can be # configured by disabling workarounds with eap_workaround=0. +# update_identifier: PPS MO ID +# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) + # Station inactivity limit # # If a station does not send anything in ap_max_inactivity seconds, an @@ -1082,6 +1211,11 @@ fast_reauth=1 # Beacon interval (default: 100 TU) #beacon_int=100 +# WPS in AP mode +# 0 = WPS enabled and configured (default) +# 1 = WPS disabled +#wps_disabled=0 + # MAC address policy # 0 = use permanent MAC address # 1 = use random MAC address for each ESS connection @@ -1144,13 +1278,13 @@ fast_reauth=1 ##### Fast Session Transfer (FST) support ##################################### # # The options in this section are only available when the build configuration -# option CONFIG_FST is set while compiling hostapd. They allow this interface -# to be a part of FST setup. +# option CONFIG_FST is set while compiling wpa_supplicant. They allow this +# interface to be a part of FST setup. # # FST is the transfer of a session from a channel to another channel, in the # same or different frequency bands. # -# For detals, see IEEE Std 802.11ad-2012. +# For details, see IEEE Std 802.11ad-2012. # Identifier of an FST Group the interface belongs to. #fst_group_id=bond0 @@ -1483,22 +1617,10 @@ network={ group=CCMP TKIP identity="user@example.com" ca_cert="/etc/cert/ca.pem" - client_cert="/etc/cert/user.pem" - - engine=1 - - # The engine configured here must be available. Look at - # OpenSSL engine support in the global section. - # The key available through the engine must be the private key - # matching the client certificate configured above. - - # use the opensc engine - #engine_id="opensc" - #key_id="45" - # use the pkcs11 engine - engine_id="pkcs11" - key_id="id_45" + # Certificate and/or key identified by PKCS#11 URI (RFC7512) + client_cert="pkcs11:manufacturer=piv_II;id=%01" + private_key="pkcs11:manufacturer=piv_II;id=%01" # Optional PIN configuration; this can be left out and PIN will be # asked through the control interface diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 58df48c..ef9273d 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -44,6 +44,7 @@ struct wpa_driver_associate_params; struct ctrl_iface_priv; struct ctrl_iface_global_priv; struct wpas_dbus_priv; +struct wpas_binder_priv; /** * struct wpa_interface - Parameters for wpa_supplicant_add_iface() @@ -228,6 +229,17 @@ struct wpa_params { char *conf_p2p_dev; #endif /* CONFIG_P2P */ +#ifdef CONFIG_MATCH_IFACE + /** + * match_ifaces - Interface descriptions to match + */ + struct wpa_interface *match_ifaces; + + /** + * match_iface_count - Number of defined matching interfaces + */ + int match_iface_count; +#endif /* CONFIG_MATCH_IFACE */ }; struct p2p_srv_bonjour { @@ -253,6 +265,7 @@ struct wpa_global { struct wpa_params params; struct ctrl_iface_global_priv *ctrl_iface; struct wpas_dbus_priv *dbus; + struct wpas_binder_priv *binder; void **drv_priv; size_t drv_count; struct os_time suspend_time; @@ -278,6 +291,7 @@ struct wpa_global { unsigned int p2p_24ghz_social_channels:1; unsigned int pending_p2ps_group:1; unsigned int pending_group_iface_for_p2ps:1; + unsigned int pending_p2ps_group_freq; #ifdef CONFIG_WIFI_DISPLAY int wifi_display; @@ -300,10 +314,14 @@ struct wpa_radio { char name[16]; /* from driver_ops get_radio_name() or empty if not * available */ unsigned int external_scan_running:1; + unsigned int num_active_works; struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */ struct dl_list work; /* struct wpa_radio_work::list entries */ }; +#define MAX_ACTIVE_WORKS 2 + + /** * struct wpa_radio_work - Radio work item */ @@ -316,6 +334,7 @@ struct wpa_radio_work { void *ctx; unsigned int started:1; struct os_reltime time; + unsigned int bands; }; int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, @@ -347,6 +366,9 @@ struct wpa_external_work { unsigned int timeout; }; +enum wpa_radio_work_band wpas_freq_to_band(int freq); +unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs); + /** * offchannel_send_action_result - Result of offchannel send Action frame */ @@ -371,11 +393,6 @@ struct wps_ap_info { u8 uuid[WPS_UUID_LEN]; }; -struct wpa_ssid_value { - u8 ssid[SSID_MAX_LEN]; - size_t ssid_len; -}; - #define WPA_FREQ_USED_BY_INFRA_STATION BIT(0) #define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1) @@ -414,6 +431,21 @@ enum wpa_supplicant_test_failure { WPAS_TEST_FAILURE_SCAN_TRIGGER, }; +struct icon_entry { + struct dl_list list; + u8 bssid[ETH_ALEN]; + u8 dialog_token; + char *file_name; + u8 *image; + size_t image_len; +}; + +struct wpa_bss_tmp_disallowed { + struct dl_list list; + u8 bssid[ETH_ALEN]; + struct os_reltime disallowed_until; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -427,12 +459,16 @@ struct wpa_supplicant { struct wpa_radio *radio; /* shared radio context */ struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */ struct wpa_supplicant *parent; + struct wpa_supplicant *p2pdev; struct wpa_supplicant *next; struct l2_packet_data *l2; struct l2_packet_data *l2_br; 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 */ @@ -443,6 +479,9 @@ struct wpa_supplicant { char *preq_notify_peer; #endif /* CONFIG_AP */ #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ +#ifdef CONFIG_CTRL_IFACE_BINDER + const void *binder_object_key; +#endif /* CONFIG_CTRL_IFACE_BINDER */ char bridge_ifname[16]; char *confname; @@ -455,7 +494,8 @@ struct wpa_supplicant { u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this * field contains the target BSSID. */ int reassociate; /* reassociation requested */ - int reassoc_same_bss; /* reassociating to the same bss */ + unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */ + unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */ int disconnected; /* all connections disabled; i.e., do no reassociate * before this has been cleared */ struct wpa_ssid *current_ssid; @@ -500,9 +540,10 @@ struct wpa_supplicant { struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */ int sched_scan_timeout; - int sched_scan_interval; int first_sched_scan; int sched_scan_timed_out; + struct sched_scan_plan *sched_scan_plans; + size_t sched_scan_plans_num; void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); @@ -533,6 +574,7 @@ struct wpa_supplicant { struct wpa_radio_work *scan_work; int scanning; int sched_scanning; + unsigned int sched_scan_stop_req:1; int new_connection; int eapol_received; /* number of EAPOL packets received after the @@ -613,6 +655,7 @@ struct wpa_supplicant { #define MAX_SCAN_ID 16 int scan_id[MAX_SCAN_ID]; unsigned int scan_id_count; + u8 next_scan_bssid[ETH_ALEN]; struct wpa_ssid_value *ssids_from_scan_req; unsigned int num_ssids_from_scan_req; @@ -634,6 +677,9 @@ struct wpa_supplicant { int max_scan_ssids; int max_sched_scan_ssids; + unsigned int max_sched_scan_plans; + unsigned int max_sched_scan_plan_interval; + unsigned int max_sched_scan_plan_iterations; int sched_scan_supported; unsigned int max_match_sets; unsigned int max_remain_on_chan; @@ -658,6 +704,7 @@ struct wpa_supplicant { unsigned int reattach:1; /* reassociation to the same BSS requested */ unsigned int mac_addr_changed:1; unsigned int added_vif:1; + unsigned int wnmsleep_used:1; struct os_reltime last_mac_addr_change; int last_mac_addr_style; @@ -722,7 +769,7 @@ struct wpa_supplicant { int mesh_if_idx; unsigned int mesh_if_created:1; unsigned int mesh_ht_enabled:1; - int mesh_auth_block_duration; /* sec */ + unsigned int mesh_vht_enabled:1; #endif /* CONFIG_MESH */ unsigned int off_channel_freq; @@ -844,6 +891,10 @@ struct wpa_supplicant { int *p2p_group_common_freqs; unsigned int p2p_group_common_freqs_num; u8 p2ps_join_addr[ETH_ALEN]; + + unsigned int p2p_go_max_oper_chwidth; + unsigned int p2p_go_vht_center_freq2; + int p2p_lo_started; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid; @@ -885,6 +936,7 @@ struct wpa_supplicant { unsigned int fetch_osu_icon_in_progress:1; struct wpa_bss *interworking_gas_bss; unsigned int osu_icon_id; + struct dl_list icon_head; /* struct icon_entry */ struct osu_provider *osu_prov; size_t osu_prov_count; struct os_reltime osu_icon_fetch_start; @@ -914,6 +966,9 @@ struct wpa_supplicant { /* WLAN_REASON_* reason codes. Negative if locally generated. */ int disconnect_reason; + /* WLAN_STATUS_* status codes from (Re)Association Response frame. */ + u16 assoc_status_code; + struct ext_password_data *ext_pw; struct wpabuf *last_gas_resp, *prev_gas_resp; @@ -969,6 +1024,10 @@ struct wpa_supplicant { struct l2_packet_data *l2_test; unsigned int extra_roc_dur; enum wpa_supplicant_test_failure test_failure; + 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; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -985,6 +1044,31 @@ struct wpa_supplicant { const struct wpabuf *fst_ies; struct wpabuf *received_mb_ies; #endif /* CONFIG_FST */ + +#ifdef CONFIG_MBO + /* Multiband operation non-preferred channel */ + struct wpa_mbo_non_pref_channel { + enum mbo_non_pref_chan_reason reason; + u8 oper_class; + u8 chan; + u8 preference; + } *non_pref_chan; + size_t non_pref_chan_num; + u8 mbo_wnm_token; +#endif /* CONFIG_MBO */ + + /* + * This should be under CONFIG_MBO, but it is left out to allow using + * the bss_temp_disallowed list for other purposes as well. + */ + struct dl_list bss_tmp_disallowed; + + /* + * Content of a measurement report element with type 8 (LCI), + * own location. + */ + struct wpabuf *lci; + struct os_reltime lci_time; }; @@ -1026,6 +1110,8 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s); void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, int reason_code); +struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s); +int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id); void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, @@ -1050,6 +1136,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s); void wpa_show_license(void); +struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global, + const char *ifname); struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, struct wpa_interface *iface, struct wpa_supplicant *parent); @@ -1079,6 +1167,7 @@ int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); +void wpas_request_disconnection(struct wpa_supplicant *wpa_s); int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen); int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style); int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s); @@ -1088,15 +1177,37 @@ void wpas_rrm_reset(struct wpa_supplicant *wpa_s); void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, const u8 *report, size_t report_len); int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, + const struct wpa_ssid_value *ssid, + int lci, int civic, void (*cb)(void *ctx, struct wpabuf *neighbor_rep), void *cb_ctx); +void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, + const u8 *src, + 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); + +/* MBO functions */ +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len); +const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, 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, + size_t len, + 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); + /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response * @wpa_s: Pointer to wpa_supplicant data @@ -1158,6 +1269,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx); +void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s); +struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s, + enum wpa_vendor_elem_frame frame); +int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, + const u8 *elem, size_t len); + #ifdef CONFIG_FST struct fst_wpa_obj; @@ -1167,4 +1284,18 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s, #endif /* CONFIG_FST */ +int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd); + +struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, + u16 num_modes, enum hostapd_hw_mode mode); + +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); + +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); + #endif /* WPA_SUPPLICANT_I_H */ diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 29c22ba..f84c8b9 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -739,6 +739,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field) return WPA_CTRL_REQ_SIM; else if (os_strcmp(field, "PSK_PASSPHRASE") == 0) return WPA_CTRL_REQ_PSK_PASSPHRASE; + else if (os_strcmp(field, "EXT_CERT_CHECK") == 0) + return WPA_CTRL_REQ_EXT_CERT_CHECK; return WPA_CTRL_REQ_UNKNOWN; } @@ -782,6 +784,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, *txt = "PSK or passphrase"; ret = "PSK_PASSPHRASE"; break; + case WPA_CTRL_REQ_EXT_CERT_CHECK: + *txt = "External server certificate validation"; + ret = "EXT_CERT_CHECK"; + break; default: break; } @@ -837,6 +843,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx, if (ssid == NULL) return; + if (field == WPA_CTRL_REQ_EXT_CERT_CHECK) + ssid->eap.pending_ext_cert_check = PENDING_CHECK; wpas_notify_network_request(wpa_s, ssid, field, default_txt); field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt, @@ -1013,7 +1021,6 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr); } -#endif /* CONFIG_NO_WPA */ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, @@ -1028,6 +1035,7 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, else return 0; } +#endif /* CONFIG_NO_WPA */ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) @@ -1124,6 +1132,7 @@ 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; } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); } diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c index 354decf..d6ec8c5 100644 --- a/wpa_supplicant/wpas_kay.c +++ b/wpa_supplicant/wpas_kay.c @@ -50,10 +50,9 @@ static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window) } -static int wpas_set_current_cipher_suite(void *wpa_s, const u8 *cs, - size_t cs_len) +static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs) { - return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len); + return wpa_drv_set_current_cipher_suite(wpa_s, cs); } @@ -109,7 +108,8 @@ static int wpas_create_receive_sc(void *wpa_s, u32 channel, enum validate_frames vf, enum confidentiality_offset co) { - return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, sci->port, + return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, + be_to_host16(sci->port), conf_offset_val(co), vf); } @@ -150,7 +150,8 @@ wpas_create_transmit_sc(void *wpa_s, u32 channel, const struct ieee802_1x_mka_sci *sci, enum confidentiality_offset co) { - return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, sci->port, + return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, + be_to_host16(sci->port), conf_offset_val(co)); } diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c index 6af1678..4e37591 100644 --- a/wpa_supplicant/wpas_module_tests.c +++ b/wpa_supplicant/wpas_module_tests.c @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/module_tests.h" #include "wpa_supplicant_i.h" #include "blacklist.h" @@ -79,30 +80,18 @@ int wpas_module_tests(void) ret = -1; #ifdef CONFIG_WPS - { - int wps_module_tests(void); - if (wps_module_tests() < 0) - ret = -1; - } + if (wps_module_tests() < 0) + ret = -1; #endif /* CONFIG_WPS */ - { - int utils_module_tests(void); - if (utils_module_tests() < 0) - ret = -1; - } - - { - int common_module_tests(void); - if (common_module_tests() < 0) - ret = -1; - } - - { - int crypto_module_tests(void); - if (crypto_module_tests() < 0) - ret = -1; - } + if (utils_module_tests() < 0) + ret = -1; + + if (common_module_tests() < 0) + ret = -1; + + if (crypto_module_tests() < 0) + ret = -1; return ret; } diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 60f761c..74a420c 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -583,8 +583,8 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, m2d->dev_password_id, m2d->config_error); wpas_notify_wps_event_m2d(wpa_s, m2d); #ifdef CONFIG_P2P - if (wpa_s->parent && wpa_s->parent != wpa_s) { - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) { + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D "dev_password_id=%d config_error=%d", m2d->dev_password_id, m2d->config_error); } @@ -617,8 +617,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", fail->msg, fail->config_error, fail->error_indication, wps_ei_str(fail->error_indication)); - if (wpa_s->parent && wpa_s->parent != wpa_s) - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", fail->msg, fail->config_error, fail->error_indication, @@ -627,8 +627,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); - if (wpa_s->parent && wpa_s->parent != wpa_s) - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); } @@ -683,6 +683,13 @@ static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx) } +int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s) +{ + return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb, + wpa_s, NULL); +} + + static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); @@ -1135,6 +1142,13 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, return -1; ssid->temporary = 1; ssid->p2p_group = p2p_group; + /* + * When starting a regular WPS process (not P2P group formation) + * the registrar/final station can be either AP or PCP + * so use a "don't care" value for the pbss flag. + */ + if (!p2p_group) + ssid->pbss = 2; #ifdef CONFIG_P2P if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); @@ -1142,6 +1156,10 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, ssid->ssid_len = wpa_s->go_params->ssid_len; os_memcpy(ssid->ssid, wpa_s->go_params->ssid, ssid->ssid_len); + if (wpa_s->go_params->freq > 56160) { + /* P2P in 60 GHz uses PBSS */ + ssid->pbss = 1; + } wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " "SSID", ssid->ssid, ssid->ssid_len); } @@ -1186,6 +1204,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, } ssid->temporary = 1; ssid->p2p_group = p2p_group; + /* + * When starting a regular WPS process (not P2P group formation) + * the registrar/final station can be either AP or PCP + * so use a "don't care" value for the pbss flag. + */ + if (!p2p_group) + ssid->pbss = 2; if (ssid_val) { ssid->ssid = os_malloc(ssid_len); if (ssid->ssid) { @@ -1209,6 +1234,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, ssid->ssid_len = wpa_s->go_params->ssid_len; os_memcpy(ssid->ssid, wpa_s->go_params->ssid, ssid->ssid_len); + if (wpa_s->go_params->freq > 56160) { + /* P2P in 60 GHz uses PBSS */ + ssid->pbss = 1; + } wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " "SSID", ssid->ssid, ssid->ssid_len); } @@ -1221,7 +1250,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"", dev_pw_id, hash); } else { - rpin = wps_generate_pin(); + if (wps_generate_pin(&rpin) < 0) { + wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN"); + return -1; + } os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"", rpin, dev_pw_id, hash); } diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 3c25ca8..c8fe47e 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -85,6 +85,7 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s); #else /* CONFIG_WPS */ @@ -147,6 +148,12 @@ static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, { } +static inline int +wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s) +{ + return 0; +} + #endif /* CONFIG_WPS */ #endif /* WPS_SUPPLICANT_H */ |