diff options
Diffstat (limited to 'wpa_supplicant')
53 files changed, 5661 insertions, 1618 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 295a897..eae00d8 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -72,6 +72,11 @@ ifdef CONFIG_DRIVER_NL80211 INCLUDES += external/libnl-headers endif +ifdef CONFIG_FIPS +CONFIG_NO_RANDOM_POOL= +CONFIG_OPENSSL_CMAC=y +endif + OBJS = config.c OBJS += notify.c OBJS += bss.c @@ -184,6 +189,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_IEEE80211V +L_CFLAGS += -DCONFIG_IEEE80211V +OBJS += wnm_sta.c +endif + ifdef CONFIG_TDLS L_CFLAGS += -DCONFIG_TDLS OBJS += src/rsn_supp/tdls.c @@ -244,6 +254,17 @@ L_CFLAGS += -DCONFIG_P2P_STRICT endif endif +ifdef CONFIG_WIFI_DISPLAY +L_CFLAGS += -DCONFIG_WIFI_DISPLAY +OBJS += wifi_display.c +endif + +ifdef CONFIG_HS20 +OBJS += hs20_supplicant.c +L_CFLAGS += -DCONFIG_HS20 +CONFIG_INTERWORKING=y +endif + ifdef CONFIG_INTERWORKING OBJS += interworking.c L_CFLAGS += -DCONFIG_INTERWORKING @@ -734,6 +755,10 @@ ifdef CONFIG_IEEE80211N L_CFLAGS += -DCONFIG_IEEE80211N endif +ifdef CONFIG_WNM +L_CFLAGS += -DCONFIG_WNM +endif + ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c @@ -746,6 +771,12 @@ L_CFLAGS += -DEAP_SERVER_WSC OBJS += src/ap/wps_hostapd.c OBJS += src/eap_server/eap_server_wsc.c endif +ifdef CONFIG_INTERWORKING +OBJS += src/ap/gas_serv.c +endif +ifdef CONFIG_HS20 +OBJS += src/ap/hs20.c +endif endif ifdef NEED_RSN_AUTHENTICATOR @@ -844,8 +875,10 @@ 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 endif +endif ifndef CONFIG_TLS CONFIG_TLS=openssl @@ -855,6 +888,11 @@ ifdef CONFIG_TLSV11 L_CFLAGS += -DCONFIG_TLSV11 endif +ifdef CONFIG_TLSV12 +L_CFLAGS += -DCONFIG_TLSV12 +NEED_SHA256=y +endif + ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS L_CFLAGS += -DEAP_TLS_OPENSSL @@ -939,6 +977,9 @@ OBJS += src/tls/pkcs8.c NEED_SHA256=y NEED_BASE64=y NEED_TLS_PRF=y +ifdef CONFIG_TLSV12 +NEED_TLS_PRF_SHA256=y +endif NEED_MODEXP=y NEED_CIPHER=y L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT @@ -1044,8 +1085,12 @@ AESOBJS += src/crypto/aes-encblock.c endif ifdef NEED_AES_OMAC1 NEED_AES_ENC=y +ifdef CONFIG_OPENSSL_CMAC +CFLAGS += -DCONFIG_OPENSSL_CMAC +else AESOBJS += src/crypto/aes-omac1.c endif +endif ifdef NEED_AES_WRAP NEED_AES_ENC=y AESOBJS += src/crypto/aes-wrap.c @@ -1065,7 +1110,10 @@ endif SHA1OBJS = ifdef NEED_SHA1 +ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += src/crypto/sha1.c +endif +SHA1OBJS += src/crypto/sha1-prf.c ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += src/crypto/sha1-internal.c ifdef NEED_FIPS186_2_PRF @@ -1075,8 +1123,10 @@ endif ifdef CONFIG_NO_WPA_PASSPHRASE L_CFLAGS += -DCONFIG_NO_PBKDF2 else +ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += src/crypto/sha1-pbkdf2.c endif +endif ifdef NEED_T_PRF SHA1OBJS += src/crypto/sha1-tprf.c endif @@ -1085,14 +1135,13 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c endif endif -MD5OBJS = src/crypto/md5.c +ifndef CONFIG_FIPS +MD5OBJS += src/crypto/md5.c +endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 MD5OBJS += src/crypto/md5-internal.c endif -ifdef CONFIG_FIPS -MD5OBJS += src/crypto/md5-non-fips.c -endif OBJS += $(MD5OBJS) OBJS_p += $(MD5OBJS) endif @@ -1119,10 +1168,16 @@ endif SHA256OBJS = # none by default ifdef NEED_SHA256 L_CFLAGS += -DCONFIG_SHA256 +ifneq ($(CONFIG_TLS), openssl) SHA256OBJS += src/crypto/sha256.c +endif +SHA256OBJS += src/crypto/sha256-prf.c ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += src/crypto/sha256-internal.c endif +ifdef NEED_TLS_PRF_SHA256 +SHA256OBJS += src/crypto/sha256-tlsprf.c +endif OBJS += $(SHA256OBJS) endif @@ -1162,6 +1217,11 @@ endif ifeq ($(CONFIG_CTRL_IFACE), named_pipe) L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE endif +ifeq ($(CONFIG_CTRL_IFACE), udp-remote) +CONFIG_CTRL_IFACE=udp +L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP +L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +endif OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c endif @@ -1282,6 +1342,10 @@ L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)" endif endif +ifdef CONFIG_DEBUG_LINUX_TRACING +L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING +endif + ifdef CONFIG_DEBUG_FILE L_CFLAGS += -DCONFIG_DEBUG_FILE endif @@ -1297,6 +1361,7 @@ endif OBJS += $(SHA1OBJS) $(DESOBJS) OBJS_p += $(SHA1OBJS) +OBJS_p += $(SHA256OBJS) ifdef CONFIG_BGSCAN_SIMPLE L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE @@ -1332,8 +1397,19 @@ L_CFLAGS += -DCONFIG_AUTOSCAN OBJS += autoscan.c endif +ifdef CONFIG_EXT_PASSWORD_TEST +OBJS += src/utils/ext_password_test.c +L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST +NEED_EXT_PASSWORD=y +endif + +ifdef NEED_EXT_PASSWORD +OBJS += src/utils/ext_password.c +L_CFLAGS += -DCONFIG_EXT_PASSWORD +endif + ifdef NEED_GAS -OBJS += ../src/common/gas.c +OBJS += src/common/gas.c OBJS += gas_query.c L_CFLAGS += -DCONFIG_GAS NEED_OFFCHANNEL=y @@ -1371,6 +1447,9 @@ OBJS_priv += src/utils/common.c OBJS_priv += src/utils/wpa_debug.c OBJS_priv += src/utils/wpabuf.c OBJS_priv += wpa_priv.c +ifdef CONFIG_DRIVER_NL80211 +OBJS_priv += src/common/ieee802_11_common.c +endif ifdef CONFIG_DRIVER_TEST OBJS_priv += $(SHA1OBJS) OBJS_priv += $(MD5OBJS) diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 6756e54..227fb4f 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -55,6 +55,11 @@ $(DESTDIR)$(BINDIR)/%: % install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL)) $(MAKE) -C ../src install +ifdef CONFIG_FIPS +CONFIG_NO_RANDOM_POOL= +CONFIG_OPENSSL_CMAC=y +endif + OBJS = config.o OBJS += notify.o OBJS += bss.o @@ -167,6 +172,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_IEEE80211V +CFLAGS += -DCONFIG_IEEE80211V +OBJS += wnm_sta.o +endif + ifdef CONFIG_TDLS CFLAGS += -DCONFIG_TDLS OBJS += ../src/rsn_supp/tdls.o @@ -227,6 +237,11 @@ CFLAGS += -DCONFIG_P2P_STRICT endif endif +ifdef CONFIG_WIFI_DISPLAY +CFLAGS += -DCONFIG_WIFI_DISPLAY +OBJS += wifi_display.o +endif + ifdef CONFIG_HS20 OBJS += hs20_supplicant.o CFLAGS += -DCONFIG_HS20 @@ -296,6 +311,17 @@ TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif +ifdef CONFIG_EAP_UNAUTH_TLS +# EAP-UNAUTH-TLS +CFLAGS += -DEAP_UNAUTH_TLS +ifndef CONFIG_EAP_UNAUTH_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 +endif + ifdef CONFIG_EAP_PEAP # EAP-PEAP ifeq ($(CONFIG_EAP_PEAP), dyn) @@ -741,6 +767,9 @@ endif ifdef CONFIG_INTERWORKING OBJS += ../src/ap/gas_serv.o endif +ifdef CONFIG_HS20 +OBJS += ../src/ap/hs20.o +endif endif ifdef NEED_RSN_AUTHENTICATOR @@ -839,8 +868,10 @@ 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 endif +endif ifndef CONFIG_TLS CONFIG_TLS=openssl @@ -868,6 +899,10 @@ OBJS += ../src/crypto/fips_prf_openssl.o endif LIBS += -lcrypto LIBS_p += -lcrypto +ifdef CONFIG_TLS_ADD_DL +LIBS += -ldl +LIBS_p += -ldl +endif endif ifeq ($(CONFIG_TLS), gnutls) @@ -1047,8 +1082,12 @@ AESOBJS += ../src/crypto/aes-encblock.o endif ifdef NEED_AES_OMAC1 NEED_AES_ENC=y +ifdef CONFIG_OPENSSL_CMAC +CFLAGS += -DCONFIG_OPENSSL_CMAC +else AESOBJS += ../src/crypto/aes-omac1.o endif +endif ifdef NEED_AES_WRAP NEED_AES_ENC=y AESOBJS += ../src/crypto/aes-wrap.o @@ -1067,7 +1106,10 @@ OBJS += $(AESOBJS) endif ifdef NEED_SHA1 +ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += ../src/crypto/sha1.o +endif +SHA1OBJS += ../src/crypto/sha1-prf.o ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += ../src/crypto/sha1-internal.o ifdef NEED_FIPS186_2_PRF @@ -1077,8 +1119,10 @@ endif ifdef CONFIG_NO_WPA_PASSPHRASE CFLAGS += -DCONFIG_NO_PBKDF2 else +ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += ../src/crypto/sha1-pbkdf2.o endif +endif ifdef NEED_T_PRF SHA1OBJS += ../src/crypto/sha1-tprf.o endif @@ -1087,14 +1131,13 @@ SHA1OBJS += ../src/crypto/sha1-tlsprf.o endif endif -MD5OBJS = ../src/crypto/md5.o +ifndef CONFIG_FIPS +MD5OBJS += ../src/crypto/md5.o +endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 MD5OBJS += ../src/crypto/md5-internal.o endif -ifdef CONFIG_FIPS -MD5OBJS += ../src/crypto/md5-non-fips.o -endif OBJS += $(MD5OBJS) OBJS_p += $(MD5OBJS) endif @@ -1121,7 +1164,10 @@ endif SHA256OBJS = # none by default ifdef NEED_SHA256 CFLAGS += -DCONFIG_SHA256 +ifneq ($(CONFIG_TLS), openssl) SHA256OBJS += ../src/crypto/sha256.o +endif +SHA256OBJS += ../src/crypto/sha256-prf.o ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += ../src/crypto/sha256-internal.o endif @@ -1167,6 +1213,11 @@ endif ifeq ($(CONFIG_CTRL_IFACE), named_pipe) CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE endif +ifeq ($(CONFIG_CTRL_IFACE), udp-remote) +CONFIG_CTRL_IFACE=udp +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +endif OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o endif @@ -1297,6 +1348,9 @@ endif ifdef CONFIG_FIPS CFLAGS += -DCONFIG_FIPS +ifneq ($(CONFIG_TLS), openssl) +$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl) +endif endif OBJS += $(SHA1OBJS) $(DESOBJS) @@ -1338,6 +1392,17 @@ CFLAGS += -DCONFIG_AUTOSCAN OBJS += autoscan.o endif +ifdef CONFIG_EXT_PASSWORD_TEST +OBJS += ../src/utils/ext_password_test.o +CFLAGS += -DCONFIG_EXT_PASSWORD_TEST +NEED_EXT_PASSWORD=y +endif + +ifdef NEED_EXT_PASSWORD +OBJS += ../src/utils/ext_password.o +CFLAGS += -DCONFIG_EXT_PASSWORD +endif + ifdef NEED_GAS OBJS += ../src/common/gas.o OBJS += gas_query.o @@ -1559,6 +1624,11 @@ test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS) tests: test-eap_sim_common +FIPSDIR=/usr/local/ssl/fips-2.0 +FIPSLD=$(FIPSDIR)/bin/fipsld +fips: + $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)" + clean: $(MAKE) -C ../src clean $(MAKE) -C dbus clean diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 new file mode 100644 index 0000000..feb9049 --- /dev/null +++ b/wpa_supplicant/README-HS20 @@ -0,0 +1,470 @@ +wpa_supplicant and Hotspot 2.0 +============================== + +This document describe how the IEEE 802.11u Interworking and Wi-Fi +Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be +configured and how an external component on the client e.g., management +GUI or Wi-Fi framework) is used to manage this functionality. + + +Introduction to Wi-Fi Hotspot 2.0 +--------------------------------- + +Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used +in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about +this is available in this white paper: + +http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless + +The Hotspot 2.0 specification is also available from WFA: +https://www.wi-fi.org/knowledge-center/published-specifications + +The core Interworking functionality (network selection, GAS/ANQP) were +standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std +802.11-2012. + + +wpa_supplicant network selection +-------------------------------- + +Interworking support added option for configuring credentials that can +work with multiple networks as an alternative to configuration of +network blocks (e.g., per-SSID parameters). When requested to perform +network selection, wpa_supplicant picks the highest priority enabled +network block or credential. If a credential is picked (based on ANQP +information from APs), a temporary network block is created +automatically for the matching network. This temporary network block is +used similarly to the network blocks that can be configured by the user, +but it is not stored into the configuration file and is meant to be used +only for temporary period of time since a new one can be created +whenever needed based on ANQP information and the credential. + +By default, wpa_supplicant is not using automatic network selection +unless requested explicitly with the interworking_select command. This +can be changed with the auto_interworking=1 parameter to perform network +selection automatically whenever trying to find a network for connection +and none of the enabled network blocks match with the scan results. This +case works similarly to "interworking_select auto", i.e., wpa_supplicant +will internally determine which network or credential is going to be +used based on configured priorities, scan results, and ANQP information. + + +wpa_supplicant configuration +---------------------------- + +Interworking and Hotspot 2.0 functionality are optional components that +need to be enabled in the wpa_supplicant build configuration +(.config). This is done by adding following parameters into that file: + +CONFIG_INTERWORKING=y +CONFIG_HS20=y + +It should be noted that this functionality requires a driver that +supports GAS/ANQP operations. This uses the same design as P2P, i.e., +Action frame processing and building in user space within +wpa_supplicant. The Linux nl80211 driver interface provides the needed +functionality for this. + + +There are number of run-time configuration parameters (e.g., in +wpa_supplicant.conf when using the configuration file) that can be used +to control Hotspot 2.0 operations. + +# Enable Interworking +interworking=1 + +# Enable Hotspot 2.0 +hs20=1 + +# Parameters for controlling scanning + +# Homogenous ESS identifier +# If this is set, scans will be used to request response only from BSSes +# belonging to the specified Homogeneous ESS. This is used only if interworking +# is enabled. +#hessid=00:11:22:33:44:55 + +# Access Network Type +# When Interworking is enabled, scans can be limited to APs that advertise the +# specified Access Network Type (0..15; with 15 indicating wildcard match). +# This value controls the Access Network Type value in Probe Request frames. +#access_network_type=15 + +# Automatic network selection behavior +# 0 = do not automatically go through Interworking network selection +# (i.e., require explicit interworking_select command for this; default) +# 1 = perform Interworking network selection if one or more +# credentials have been configured and scan did not find a +# matching network block +#auto_interworking=0 + + +Credentials can be pre-configured for automatic network selection: + +# credential block +# +# Each credential used for automatic network selection is configured as a set +# of parameters that are compared to the information advertised by the APs when +# interworking_select and interworking_connect commands are used. +# +# credential fields: +# +# priority: Priority group +# By default, all networks and credentials get the same priority group +# (0). This field can be used to give higher priority for credentials +# (and similarly in struct wpa_ssid for network blocks) to change the +# Interworking automatic networking selection behavior. The matching +# network (based on either an enabled network block or a credential) +# with the highest priority value will be selected. +# +# pcsc: Use PC/SC and SIM/USIM card +# +# realm: Home Realm for Interworking +# +# username: Username for Interworking network selection +# +# password: Password for Interworking network selection +# +# ca_cert: CA certificate for Interworking network selection +# +# client_cert: File path to client certificate file (PEM/DER) +# This field is used with Interworking networking selection for a case +# where client certificate/private key is used for authentication +# (EAP-TLS). Full path to the file should be used since working +# directory may change when wpa_supplicant is run in the background. +# +# Alternatively, a named configuration blob can be used by setting +# this to blob://blob_name. +# +# private_key: File path to client private key file (PEM/DER/PFX) +# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be +# commented out. Both the private key and certificate will be read +# from the PKCS#12 file in this case. Full path to the file should be +# used since working directory may change when wpa_supplicant is run +# in the background. +# +# Windows certificate store can be used by leaving client_cert out and +# configuring private_key in one of the following formats: +# +# cert://substring_to_match +# +# hash://certificate_thumbprint_in_hex +# +# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" +# +# Note that when running wpa_supplicant as an application, the user +# certificate store (My user account) is used, whereas computer store +# (Computer account) is used when running wpasvc as a service. +# +# Alternatively, a named configuration blob can be used by setting +# this to blob://blob_name. +# +# private_key_passwd: Password for private key file +# +# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format +# +# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> +# format +# +# domain: Home service provider FQDN +# This is used to compare against the Domain Name List to figure out +# whether the AP is operated by the Home SP. +# +# roaming_consortium: Roaming Consortium OI +# If roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that can be used to determine which access +# points support authentication with this credential. This is an +# alternative to the use of the realm parameter. When using Roaming +# Consortium to match the network, the EAP parameters need to be +# pre-configured with the credential since the NAI Realm information +# may not be available or fetched. +# +# eap: Pre-configured EAP method +# This optional field can be used to specify which EAP method will be +# used with this credential. If not set, the EAP method is selected +# automatically based on ANQP information (e.g., NAI Realm). +# +# phase1: Pre-configure Phase 1 (outer authentication) parameters +# This optional field is used with like the 'eap' parameter. +# +# phase2: Pre-configure Phase 2 (inner authentication) parameters +# This optional field is used with like the 'eap' parameter. +# +# for example: +# +#cred={ +# realm="example.com" +# username="user@example.com" +# password="password" +# ca_cert="/etc/wpa_supplicant/ca.pem" +# domain="example.com" +#} +# +#cred={ +# imsi="310026-000000000" +# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82" +#} +# +#cred={ +# realm="example.com" +# username="user" +# password="password" +# ca_cert="/etc/wpa_supplicant/ca.pem" +# domain="example.com" +# roaming_consortium=223344 +# eap=TTLS +# phase2="auth=MSCHAPV2" +#} + + +Control interface +----------------- + +wpa_supplicant provides a control interface that can be used from +external programs to manage various operations. The included command +line tool, wpa_cli, can be used for manual testing with this interface. + +Following wpa_cli interactive mode commands show some examples of manual +operations related to Hotspot 2.0: + +Remove configured networks and credentials: + +> remove_network all +OK +> remove_cred all +OK + + +Add a username/password credential: + +> add_cred +0 +> set_cred 0 realm "mail.example.com" +OK +> set_cred 0 username "username" +OK +> set_cred 0 password "password" +OK +> set_cred 0 priority 1 +OK + +Add a SIM credential using a simulated SIM/USIM card for testing: + +> add_cred +1 +> set_cred 1 imsi "23456-0000000000" +OK +> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123" +OK +> set_cred 1 priority 1 +OK + +Note: the return value of add_cred is used as the first argument to +the following set_cred commands. + + +Add a WPA2-Enterprise network: + +> add_network +0 +> set_network 0 key_mgmt WPA-EAP +OK +> set_network 0 ssid "enterprise" +OK +> set_network 0 eap TTLS +OK +> set_network 0 anonymous_identity "anonymous" +OK +> set_network 0 identity "user" +OK +> set_network 0 password "password" +OK +> set_network 0 priority 0 +OK +> enable_network 0 no-connect +OK + + +Add an open network: + +> add_network +3 +> set_network 3 key_mgmt NONE +OK +> set_network 3 ssid "coffee-shop" +OK +> select_network 3 +OK + +Note: the return value of add_network is used as the first argument to +the following set_network commands. + +The preferred credentials/networks can be indicated with the priority +parameter (1 is higher priority than 0). + + +Interworking network selection can be started with interworking_select +command. This instructs wpa_supplicant to run a network scan and iterate +through the discovered APs to request ANQP information from the APs that +advertise support for Interworking/Hotspot 2.0: + +> interworking_select +OK +<3>Starting ANQP fetch for 02:00:00:00:01:00 +<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list +<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 +<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown + + +INTERWORKING-AP event messages indicate the APs that support network +selection and for which there is a matching +credential. interworking_connect command can be used to select a network +to connect with: + + +> interworking_connect 02:00:00:00:01:00 +OK +<3>CTRL-EVENT-SCAN-RESULTS +<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Associated with 02:00:00:00:01:00 +<3>CTRL-EVENT-EAP-STARTED EAP authentication started +<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 +<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected +<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully +<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP] +<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=] + + +wpa_supplicant creates a temporary network block for the selected +network based on the configured credential and ANQP information from the +AP: + +> list_networks +network id / ssid / bssid / flags +0 Example Network any [CURRENT] +> get_network 0 key_mgmt +WPA-EAP +> get_network 0 eap +TTLS + + +Alternatively to using an external program to select the network, +"interworking_select auto" command can be used to request wpa_supplicant +to select which network to use based on configured priorities: + + +> remove_network all +OK +<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1 +> interworking_select auto +OK +<3>Starting ANQP fetch for 02:00:00:00:01:00 +<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list +<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 +<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown +<3>CTRL-EVENT-SCAN-RESULTS +<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Associated with 02:00:00:00:01:00 +<3>CTRL-EVENT-EAP-STARTED EAP authentication started +<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 +<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected +<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully +<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP] +<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=] + + +The connection status can be shown with the status command: + +> status +bssid=02:00:00:00:01:00 +ssid=Example Network +id=0 +mode=station +pairwise_cipher=CCMP <--- link layer security indication +group_cipher=CCMP +key_mgmt=WPA2/IEEE 802.1X/EAP +wpa_state=COMPLETED +p2p_device_address=02:00:00:00:00:00 +address=02:00:00:00:00:00 +hs20=1 <--- HS 2.0 indication +Supplicant PAE state=AUTHENTICATED +suppPortStatus=Authorized +EAP state=SUCCESS +selectedMethod=21 (EAP-TTLS) +EAP TLS cipher=AES-128-SHA +EAP-TTLSv0 Phase2 method=PAP + + +> status +bssid=02:00:00:00:02:00 +ssid=coffee-shop +id=3 +mode=station +pairwise_cipher=NONE +group_cipher=NONE +key_mgmt=NONE +wpa_state=COMPLETED +p2p_device_address=02:00:00:00:00:00 +address=02:00:00:00:00:00 + + +Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status +command output. Link layer security is indicated with the +pairwise_cipher (CCMP = secure, NONE = no encryption used). + + +Also the scan results include the Hotspot 2.0 indication: + +> scan_results +bssid / frequency / signal level / flags / ssid +02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network + + +ANQP information for the BSS can be fetched using the BSS command: + +> bss 02:00:00:00:01:00 +id=1 +bssid=02:00:00:00:01:00 +freq=2412 +beacon_int=100 +capabilities=0x0411 +qual=0 +noise=-92 +level=-30 +tsf=1345573286517276 +age=105 +ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000 +flags=[WPA2-EAP-CCMP][ESS][HS20] +ssid=Example Network +anqp_roaming_consortium=031122330510203040500601020304050603fedcba + + +ANQP queries can also be requested with the anqp_get and hs20_anqp_get +commands: + +> anqp_get 02:00:00:00:01:00 261 +OK +<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list +> hs20_anqp_get 02:00:00:00:01:00 2 +OK +<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List + +In addition, fetch_anqp command can be used to request similar set of +ANQP queries to be done as is run as part of interworking_select: + +> scan +OK +<3>CTRL-EVENT-SCAN-RESULTS +> fetch_anqp +OK +<3>Starting ANQP fetch for 02:00:00:00:01:00 +<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list +<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 diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index bb4c2ad..6b81397 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -71,7 +71,8 @@ over the main control interface. Device Discovery -p2p_find [timeout in seconds] [type=<social|progressive>] +p2p_find [timeout in seconds] [type=<social|progressive>] \ + [dev_id=<addr>] [delay=<search delay in ms>] The default behavior is to run a single full scan in the beginning and then scan only social channels. type=social will scan only social @@ -81,6 +82,11 @@ progressively one channel at the time in the Search state rounds. This will help in finding new groups or groups missed during the initial full scan. +The optional dev_id option can be used to specify a single P2P peer to +search for. The optional delay parameter can be used to request an extra +delay to be used between search iterations (e.g., to free up radio +resources for concurrent operations). + p2p_listen [timeout in seconds] Start Listen-only state (become discoverable without searching for @@ -250,6 +256,14 @@ p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:Content p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1 +# Wi-Fi Display examples +# format: wifi-display <list of roles> <list of subelements> +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5 +p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3 +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2 +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5 +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5 + p2p_serv_disc_cancel_req <query identifier> Cancel a pending P2P service discovery request. This command takes a diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index fc0614d..d71d1d3 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -495,3 +495,6 @@ CONFIG_NO_ROAMING=y # Enable P2P CONFIG_P2P=y CONFIG_AP=y + +#Enable Wifi Display +CONFIG_WIFI_DISPLAY=y diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index f9e0045..3798f5a 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -99,6 +99,18 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, if (!no_ht && mode && mode->ht_capab) { conf->ieee80211n = 1; +#ifdef CONFIG_P2P + if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && + (mode->ht_capab & + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && + ssid->ht40) + conf->secondary_channel = + wpas_p2p_get_ht40_mode(wpa_s, mode, + conf->channel); + if (conf->secondary_channel) + conf->ht_capab |= + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; +#endif /* CONFIG_P2P */ /* * white-list capabilities that won't cause issues @@ -150,7 +162,6 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, return -1; } os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len); - bss->ssid.ssid[ssid->ssid_len] = '\0'; bss->ssid.ssid_len = ssid->ssid_len; bss->ssid.ssid_set = 1; @@ -207,6 +218,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, } if (pairwise & WPA_CIPHER_TKIP) bss->wpa_group = WPA_CIPHER_TKIP; + else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == + WPA_CIPHER_GCMP) + bss->wpa_group = WPA_CIPHER_GCMP; else bss->wpa_group = WPA_CIPHER_CCMP; @@ -450,6 +464,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, if (ssid->pairwise_cipher & WPA_CIPHER_CCMP) wpa_s->pairwise_cipher = WPA_CIPHER_CCMP; + else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP) + wpa_s->pairwise_cipher = WPA_CIPHER_GCMP; else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP) wpa_s->pairwise_cipher = WPA_CIPHER_TKIP; else if (ssid->pairwise_cipher & WPA_CIPHER_NONE) @@ -491,6 +507,10 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, return -1; } + os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params, + wpa_s->conf->wmm_ac_params, + sizeof(wpa_s->conf->wmm_ac_params)); + if (params.uapsd > 0) { conf->bss->wmm_enabled = 1; conf->bss->wmm_uapsd = 1; @@ -511,7 +531,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, #endif /* CONFIG_P2P */ hapd_iface->num_bss = conf->num_bss; - hapd_iface->bss = os_zalloc(conf->num_bss * + hapd_iface->bss = os_calloc(conf->num_bss, sizeof(struct hostapd_data *)); if (hapd_iface->bss == NULL) { wpa_supplicant_ap_deinit(wpa_s); diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c index ed4d879..adf82d8 100644 --- a/wpa_supplicant/bgscan_learn.c +++ b/wpa_supplicant/bgscan_learn.c @@ -75,7 +75,7 @@ static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss, if (bssid_in_array(bss->neigh, bss->num_neigh, bssid)) return; - n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN); + n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN); if (n == NULL) return; @@ -219,7 +219,7 @@ static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data, dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { if (in_array(freqs, bss->freq)) continue; - n = os_realloc(freqs, (*count + 2) * sizeof(int)); + n = os_realloc_array(freqs, *count + 2, sizeof(int)); if (n == NULL) return freqs; freqs = n; @@ -248,7 +248,7 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq " "%u", data->supp_freqs[idx]); data->probe_idx = idx; - n = os_realloc(freqs, (count + 2) * sizeof(int)); + n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) return freqs; freqs = n; @@ -360,7 +360,7 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s) for (j = 0; j < modes[i].num_channels; j++) { if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED) continue; - n = os_realloc(freqs, (count + 2) * sizeof(int)); + n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) continue; diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b89732d..be21029 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -53,42 +53,6 @@ struct parse_data { }; -static char * wpa_config_parse_string(const char *value, size_t *len) -{ - if (*value == '"') { - const char *pos; - char *str; - value++; - pos = os_strrchr(value, '"'); - if (pos == NULL || pos[1] != '\0') - return NULL; - *len = pos - value; - str = os_malloc(*len + 1); - if (str == NULL) - return NULL; - os_memcpy(str, value, *len); - str[*len] = '\0'; - return str; - } else { - u8 *str; - size_t tlen, hlen = os_strlen(value); - if (hlen & 1) - return NULL; - tlen = hlen / 2; - str = os_malloc(tlen + 1); - if (str == NULL) - return NULL; - if (hexstr2bin(value, str, tlen)) { - os_free(str); - return NULL; - } - str[tlen] = '\0'; - *len = tlen; - return (char *) str; - } -} - - static int wpa_config_parse_str(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) @@ -149,18 +113,6 @@ set: #ifndef NO_CONFIG_WRITE -static int is_hex(const u8 *data, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (data[i] < 32 || data[i] >= 127) - return 1; - } - return 0; -} - - static char * wpa_config_write_string_ascii(const u8 *value, size_t len) { char *buf; @@ -219,26 +171,6 @@ static char * wpa_config_write_str(const struct parse_data *data, return wpa_config_write_string((const u8 *) *src, len); } - -#ifdef WPA_UNICODE_SSID -static char * wpa_config_write_str_unicode(const struct parse_data *data, - struct wpa_ssid *ssid) -{ - size_t len; - char **src; - - src = (char **) (((u8 *) ssid) + (long) data->param1); - if (*src == NULL) - return NULL; - - if (data->param2) - len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); - else - len = os_strlen(*src); - - return wpa_config_write_string_ascii((const u8 *) *src, len); -} -#endif #endif /* NO_CONFIG_WRITE */ @@ -344,6 +276,21 @@ static int wpa_config_parse_psk(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { +#ifdef CONFIG_EXT_PASSWORD + if (os_strncmp(value, "ext:", 4) == 0) { + os_free(ssid->passphrase); + ssid->passphrase = NULL; + ssid->psk_set = 0; + os_free(ssid->ext_psk); + ssid->ext_psk = os_strdup(value + 4); + if (ssid->ext_psk == NULL) + return -1; + wpa_printf(MSG_DEBUG, "PSK: External password '%s'", + ssid->ext_psk); + return 0; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (*value == '"') { #ifndef CONFIG_NO_PBKDF2 const char *pos; @@ -401,6 +348,17 @@ static int wpa_config_parse_psk(const struct parse_data *data, static char * wpa_config_write_psk(const struct parse_data *data, struct wpa_ssid *ssid) { +#ifdef CONFIG_EXT_PASSWORD + if (ssid->ext_psk) { + size_t len = 4 + os_strlen(ssid->ext_psk) + 1; + char *buf = os_malloc(len); + if (buf == NULL) + return NULL; + os_snprintf(buf, len, "ext:%s", ssid->ext_psk); + return buf; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (ssid->passphrase) return wpa_config_write_string_ascii( (const u8 *) ssid->passphrase, @@ -685,6 +643,8 @@ static int wpa_config_parse_cipher(int line, const char *value) *end = '\0'; if (os_strcmp(start, "CCMP") == 0) val |= WPA_CIPHER_CCMP; + else if (os_strcmp(start, "GCMP") == 0) + val |= WPA_CIPHER_GCMP; else if (os_strcmp(start, "TKIP") == 0) val |= WPA_CIPHER_TKIP; else if (os_strcmp(start, "WEP104") == 0) @@ -736,6 +696,16 @@ static char * wpa_config_write_cipher(int cipher) pos += ret; } + if (cipher & WPA_CIPHER_GCMP) { + ret = os_snprintf(pos, end - pos, "%sGCMP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + if (cipher & WPA_CIPHER_TKIP) { ret = os_snprintf(pos, end - pos, "%sTKIP", pos == buf ? "" : " "); @@ -789,7 +759,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data, val = wpa_config_parse_cipher(line, value); if (val == -1) return -1; - if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) { + if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | + WPA_CIPHER_NONE)) { wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " "(0x%x).", line, val); return -1; @@ -818,8 +789,8 @@ static int wpa_config_parse_group(const struct parse_data *data, val = wpa_config_parse_cipher(line, value); if (val == -1) return -1; - if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | - WPA_CIPHER_WEP40)) { + if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | + WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) { wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " "(0x%x).", line, val); return -1; @@ -949,7 +920,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data, used = 0; len = 10; - freqs = os_zalloc((len + 1) * sizeof(int)); + freqs = os_calloc(len + 1, sizeof(int)); if (freqs == NULL) return NULL; @@ -960,7 +931,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data, if (used == len) { int *n; size_t i; - n = os_realloc(freqs, (len * 2 + 1) * sizeof(int)); + n = os_realloc_array(freqs, len * 2 + 1, sizeof(int)); if (n == NULL) { os_free(freqs); return NULL; @@ -1089,8 +1060,8 @@ static int wpa_config_parse_eap(const struct parse_data *data, last = *end == '\0'; *end = '\0'; tmp = methods; - methods = os_realloc(methods, - (num_methods + 1) * sizeof(*methods)); + methods = os_realloc_array(methods, num_methods + 1, + sizeof(*methods)); if (methods == NULL) { os_free(tmp); os_free(buf); @@ -1120,7 +1091,7 @@ static int wpa_config_parse_eap(const struct parse_data *data, os_free(buf); tmp = methods; - methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods)); + methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods)); if (methods == NULL) { os_free(tmp); return -1; @@ -1186,6 +1157,20 @@ static int wpa_config_parse_password(const struct parse_data *data, return 0; } +#ifdef CONFIG_EXT_PASSWORD + if (os_strncmp(value, "ext:", 4) == 0) { + char *name = os_strdup(value + 4); + if (name == NULL) + return -1; + os_free(ssid->eap.password); + ssid->eap.password = (u8 *) name; + ssid->eap.password_len = os_strlen(name); + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD; + return 0; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (os_strncmp(value, "hash:", 5) != 0) { char *tmp; size_t res_len; @@ -1203,6 +1188,7 @@ static int wpa_config_parse_password(const struct parse_data *data, ssid->eap.password = (u8 *) tmp; ssid->eap.password_len = res_len; ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } @@ -1231,6 +1217,7 @@ static int wpa_config_parse_password(const struct parse_data *data, ssid->eap.password = hash; ssid->eap.password_len = 16; ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } @@ -1244,6 +1231,17 @@ static char * wpa_config_write_password(const struct parse_data *data, if (ssid->eap.password == NULL) return NULL; +#ifdef CONFIG_EXT_PASSWORD + if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { + buf = os_zalloc(4 + ssid->eap.password_len + 1); + if (buf == NULL) + return NULL; + os_memcpy(buf, "ext:", 4); + os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len); + return buf; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { return wpa_config_write_string( ssid->eap.password, ssid->eap.password_len); @@ -1391,18 +1389,27 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data, pos++; if (hwaddr_aton(pos, addr)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "p2p_client_list address '%s'.", - line, value); - /* continue anyway */ + if (count == 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid " + "p2p_client_list address '%s'.", + line, value); + os_free(buf); + return -1; + } + /* continue anyway since this could have been from a + * truncated configuration file line */ + wpa_printf(MSG_INFO, "Line %d: Ignore likely " + "truncated p2p_client_list address '%s'", + line, pos); } else { - n = os_realloc(buf, (count + 1) * ETH_ALEN); + n = os_realloc_array(buf, count + 1, ETH_ALEN); if (n == NULL) { os_free(buf); return -1; } buf = n; - os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN); + os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN); + os_memcpy(buf, addr, ETH_ALEN); count++; wpa_hexdump(MSG_MSGDUMP, "p2p_client_list", addr, ETH_ALEN); @@ -1436,10 +1443,10 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data, pos = value; end = value + 20 * ssid->num_p2p_clients; - for (i = 0; i < ssid->num_p2p_clients; i++) { + for (i = ssid->num_p2p_clients; i > 0; i--) { res = os_snprintf(pos, end - pos, MACSTR " ", MAC2STR(ssid->p2p_client_list + - i * ETH_ALEN)); + (i - 1) * ETH_ALEN)); if (res < 0 || res >= end - pos) { os_free(value); return NULL; @@ -1500,15 +1507,6 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data, OFFSET(f), (void *) 0 #define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ OFFSET(eap.f), (void *) 0 -#ifdef WPA_UNICODE_SSID -/* STR_* variants that do not force conversion to ASCII */ -#define _STR_UNICODE(f) #f, wpa_config_parse_str, wpa_config_write_str_unicode, OFFSET(f) -#define STR_UNICODE(f) _STR_UNICODE(f), NULL, NULL, NULL, 0 -#define _STR_LEN_UNICODE(f) _STR_UNICODE(f), OFFSET(f ## _len) -#define STR_LEN_UNICODE(f) _STR_LEN_UNICODE(f), NULL, NULL, 0 -#define _STR_RANGE_UNICODE(f, min, max) _STR_LEN_UNICODE(f), (void *) (min), (void *) (max) -#define STR_RANGE_UNICODE(f, min, max) _STR_RANGE_UNICODE(f, min, max), 0 -#endif #endif /* NO_CONFIG_WRITE */ /* INT: Define an integer variable */ @@ -1553,11 +1551,7 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data, * functions. */ static const struct parse_data ssid_fields[] = { -#ifdef WPA_UNICODE_SSID - { STR_RANGE_UNICODE(ssid, 0, MAX_SSID_LEN) }, -#else { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, -#endif { INT_RANGE(scan_ssid, 0, 1) }, { FUNC(bssid) }, { FUNC_KEY(psk) }, @@ -1646,15 +1640,6 @@ static const struct parse_data ssid_fields[] = { { INT(dtim_period) }, }; -#ifdef WPA_UNICODE_SSID -#undef _STR_UNICODE -#undef STR_UNICODE -#undef _STR_LEN_UNICODE -#undef STR_LEN_UNICODE -#undef _STR_RANGE_UNICODE -#undef STR_RANGE_UNICODE -#endif - #undef OFFSET #undef _STR #undef STR @@ -1706,8 +1691,8 @@ int wpa_config_add_prio_network(struct wpa_config *config, } /* First network for this priority - add a new priority list */ - nlist = os_realloc(config->pssid, - (config->num_prio + 1) * sizeof(struct wpa_ssid *)); + nlist = os_realloc_array(config->pssid, config->num_prio + 1, + sizeof(struct wpa_ssid *)); if (nlist == NULL) return -1; @@ -1813,6 +1798,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid) { os_free(ssid->ssid); os_free(ssid->passphrase); + os_free(ssid->ext_psk); #ifdef IEEE8021X_EAPOL eap_peer_config_free(&ssid->eap); #endif /* IEEE8021X_EAPOL */ @@ -1840,6 +1826,9 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->imsi); os_free(cred->milenage); os_free(cred->domain); + os_free(cred->eap_method); + os_free(cred->phase1); + os_free(cred->phase2); os_free(cred); } @@ -1905,6 +1894,7 @@ void wpa_config_free(struct wpa_config *config) wpabuf_free(config->wps_nfc_dh_pubkey); wpabuf_free(config->wps_nfc_dh_privkey); wpabuf_free(config->wps_nfc_dev_pw); + os_free(config->ext_password_backend); os_free(config); } @@ -2139,7 +2129,7 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) get_keys = get_keys && ssid->export_keys; - props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1)); + props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *)); if (!props) return NULL; @@ -2267,8 +2257,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) void wpa_config_update_psk(struct wpa_ssid *ssid) { #ifndef CONFIG_NO_PBKDF2 - pbkdf2_sha1(ssid->passphrase, - (char *) ssid->ssid, ssid->ssid_len, 4096, + pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, ssid->psk, PMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", ssid->psk, PMK_LEN); @@ -2293,6 +2282,31 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "eap") == 0) { + struct eap_method_type method; + method.method = eap_peer_get_type(value, &method.vendor); + if (method.vendor == EAP_VENDOR_IETF && + method.method == EAP_TYPE_NONE) { + wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' " + "for a credential", line, value); + return -1; + } + os_free(cred->eap_method); + cred->eap_method = os_malloc(sizeof(*cred->eap_method)); + if (cred->eap_method == NULL) + return -1; + os_memcpy(cred->eap_method, &method, sizeof(method)); + return 0; + } + + if (os_strcmp(var, "password") == 0 && + os_strncmp(value, "ext:", 4) == 0) { + os_free(cred->password); + cred->password = os_strdup(value); + cred->ext_password = 1; + return 0; + } + val = wpa_config_parse_string(value, &len); if (val == NULL) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " @@ -2315,6 +2329,7 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, if (os_strcmp(var, "password") == 0) { os_free(cred->password); cred->password = val; + cred->ext_password = 0; return 0; } @@ -2360,6 +2375,32 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "phase1") == 0) { + os_free(cred->phase1); + cred->phase1 = val; + return 0; + } + + if (os_strcmp(var, "phase2") == 0) { + os_free(cred->phase2); + cred->phase2 = val; + return 0; + } + + if (os_strcmp(var, "roaming_consortium") == 0) { + if (len < 3 || len > sizeof(cred->roaming_consortium)) { + wpa_printf(MSG_ERROR, "Line %d: invalid " + "roaming_consortium length %d (3..15 " + "expected)", line, (int) len); + os_free(val); + return -1; + } + os_memcpy(cred->roaming_consortium, val, len); + cred->roaming_consortium_len = len; + os_free(val); + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); @@ -2530,6 +2571,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param) { struct wpa_config *config; + const int aCWmin = 4, aCWmax = 10; + const struct hostapd_wmm_ac_params ac_bk = + { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ + const struct hostapd_wmm_ac_params ac_be = + { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ + const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ + { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; + const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ + { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; config = os_zalloc(sizeof(*config)); if (config == NULL) @@ -2539,11 +2589,16 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->fast_reauth = DEFAULT_FAST_REAUTH; config->p2p_go_intent = DEFAULT_P2P_GO_INTENT; config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; + config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY; config->bss_max_count = DEFAULT_BSS_MAX_COUNT; config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; config->max_num_sta = DEFAULT_MAX_NUM_STA; config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE; + config->wmm_ac_params[0] = ac_be; + config->wmm_ac_params[1] = ac_bk; + config->wmm_ac_params[2] = ac_vi; + config->wmm_ac_params[3] = ac_vo; if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); @@ -2836,7 +2891,8 @@ static int wpa_config_process_p2p_pref_chan( pos2++; chan = atoi(pos2); - n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel)); + n = os_realloc_array(pref, num + 1, + sizeof(struct p2p_channel)); if (n == NULL) goto fail; pref = n; @@ -2950,6 +3006,7 @@ static const struct global_parse_data global_fields[] = { { INT(bss_expiration_age), 0 }, { INT(bss_expiration_scan_count), 0 }, { INT_RANGE(filter_ssids, 0, 1), 0 }, + { INT_RANGE(filter_rssi, -100, 0), 0 }, { INT(max_num_sta), 0 }, { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, #ifdef CONFIG_HS20 @@ -2963,7 +3020,10 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 }, { BIN(wps_nfc_dh_pubkey), 0 }, { BIN(wps_nfc_dh_privkey), 0 }, - { BIN(wps_nfc_dev_pw), 0 } + { BIN(wps_nfc_dev_pw), 0 }, + { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }, + { INT(p2p_go_max_inactivity), 0 }, + { INT_RANGE(auto_interworking, 0, 1), 0 }, }; #undef FUNC @@ -2998,6 +3058,25 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) break; } if (i == NUM_GLOBAL_FIELDS) { +#ifdef CONFIG_AP + if (os_strncmp(pos, "wmm_ac_", 7) == 0) { + char *tmp = os_strchr(pos, '='); + if (tmp == NULL) { + if (line < 0) + return -1; + wpa_printf(MSG_ERROR, "Line %d: invalid line " + "'%s'", line, pos); + return -1; + } + *tmp++ = '\0'; + if (hostapd_config_wmm_ac(config->wmm_ac_params, pos, + tmp)) { + wpa_printf(MSG_ERROR, "Line %d: invalid WMM " + "AC item", line); + return -1; + } + } +#endif /* CONFIG_AP */ if (line < 0) return -1; wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.", diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 46c4da2..b889ab8 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -18,6 +18,7 @@ #define DEFAULT_FAST_REAUTH 1 #define DEFAULT_P2P_GO_INTENT 7 #define DEFAULT_P2P_INTRA_BSS 1 +#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60) #define DEFAULT_BSS_MAX_COUNT 200 #define DEFAULT_BSS_EXPIRATION_AGE 180 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2 @@ -26,6 +27,7 @@ #include "config_ssid.h" #include "wps/wps.h" +#include "common/ieee802_11_common.h" struct wpa_cred { @@ -81,6 +83,11 @@ struct wpa_cred { char *password; /** + * ext_password - Whether password is a name for external storage + */ + int ext_password; + + /** * ca_cert - CA certificate for Interworking network selection */ char *ca_cert; @@ -148,6 +155,47 @@ struct wpa_cred { * whether the AP is operated by the Home SP. */ char *domain; + + /** + * roaming_consortium - Roaming Consortium OI + * + * If roaming_consortium_len is non-zero, this field contains the + * Roaming Consortium OI that can be used to determine which access + * points support authentication with this credential. This is an + * alternative to the use of the realm parameter. When using Roaming + * Consortium to match the network, the EAP parameters need to be + * pre-configured with the credential since the NAI Realm information + * may not be available or fetched. + */ + u8 roaming_consortium[15]; + + /** + * roaming_consortium_len - Length of roaming_consortium + */ + size_t roaming_consortium_len; + + /** + * eap_method - EAP method to use + * + * Pre-configured EAP method to use with this credential or %NULL to + * indicate no EAP method is selected, i.e., the method will be + * selected automatically based on ANQP information. + */ + struct eap_method_type *eap_method; + + /** + * phase1 - Phase 1 (outer authentication) parameters + * + * Pre-configured EAP parameters or %NULL. + */ + char *phase1; + + /** + * phase2 - Phase 2 (inner authentication) parameters + * + * Pre-configured EAP parameters or %NULL. + */ + char *phase2; }; @@ -165,6 +213,7 @@ struct wpa_cred { #define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11) #define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12) #define CFG_CHANGED_P2P_PREF_CHAN BIT(13) +#define CFG_CHANGED_EXT_PW_BACKEND BIT(14) /** * struct wpa_config - wpa_supplicant configuration data @@ -575,6 +624,14 @@ struct wpa_config { int filter_ssids; /** + * filter_rssi - RSSI-based scan result filtering + * + * 0 = do not filter scan results + * -n = filter scan results below -n dBm + */ + int filter_rssi; + + /** * max_num_sta - Maximum number of STAs in an AP/P2P GO */ unsigned int max_num_sta; @@ -661,6 +718,35 @@ struct wpa_config { * wps_nfc_dh_pubkey - NFC Device Password for password token */ struct wpabuf *wps_nfc_dev_pw; + + /** + * ext_password_backend - External password backend or %NULL if none + * + * format: <backend name>[:<optional backend parameters>] + */ + char *ext_password_backend; + + /* + * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity + * + * This timeout value is used in P2P GO mode to clean up + * inactive stations. + * By default: 300 seconds. + */ + int p2p_go_max_inactivity; + + struct hostapd_wmm_ac_params wmm_ac_params[4]; + + /** + * auto_interworking - Whether to use network selection automatically + * + * 0 = do not automatically go through Interworking network selection + * (i.e., require explicit interworking_select command for this) + * 1 = perform Interworking network selection if one or more + * credentials have been configured and scan did not find a + * matching network block + */ + int auto_interworking; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 8badc7b..531957a 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -19,6 +19,29 @@ #include "p2p/p2p.h" +static int newline_terminated(const char *buf, size_t buflen) +{ + size_t len = os_strlen(buf); + if (len == 0) + return 0; + if (len == buflen - 1 && buf[buflen - 1] != '\r' && + buf[len - 1] != '\n') + return 0; + return 1; +} + + +static void skip_line_end(FILE *stream) +{ + char buf[100]; + while (fgets(buf, sizeof(buf), stream)) { + buf[sizeof(buf) - 1] = '\0'; + if (newline_terminated(buf, sizeof(buf))) + return; + } +} + + /** * wpa_config_get_line - Read the next configuration file line * @s: Buffer for the line @@ -41,6 +64,15 @@ static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line, while (fgets(s, size, stream)) { (*line)++; s[size - 1] = '\0'; + if (!newline_terminated(s, size)) { + /* + * The line was truncated - skip rest of it to avoid + * confusing error messages. + */ + wpa_printf(MSG_INFO, "Long line in configuration file " + "truncated"); + skip_line_end(stream); + } pos = s; /* Skip white space from the beginning of line. */ @@ -99,12 +131,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) wpa_config_update_psk(ssid); } - if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) { - wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key " - "management, but no PSK configured.", line); - errors++; - } - if ((ssid->group_cipher & WPA_CIPHER_CCMP) && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { @@ -123,7 +149,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) { struct wpa_ssid *ssid; int errors = 0, end = 0; - char buf[256], *pos, *pos2; + char buf[2000], *pos, *pos2; wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block", *line); @@ -329,11 +355,17 @@ struct wpa_config * wpa_config_read(const char *name) int cred_id = 0; config = wpa_config_alloc_empty(NULL, NULL); - if (config == NULL) + if (config == NULL) { + wpa_printf(MSG_ERROR, "Failed to allocate config file " + "structure"); return NULL; + } + wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); f = fopen(name, "r"); if (f == NULL) { + wpa_printf(MSG_ERROR, "Failed to open config file '%s', " + "error: %s", name, strerror(errno)); os_free(config); return NULL; } @@ -378,6 +410,8 @@ struct wpa_config * wpa_config_read(const char *name) } else if (os_strncmp(pos, "blob-base64-", 12) == 0) { if (wpa_config_process_blob(config, f, &line, pos + 12) < 0) { + wpa_printf(MSG_ERROR, "Line %d: failed to " + "process blob.", line); errors++; continue; } @@ -875,6 +909,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey); write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey); write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw); + + if (config->ext_password_backend) + fprintf(f, "ext_password_backend=%s\n", + config->ext_password_backend); + if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY) + fprintf(f, "p2p_go_max_inactivity=%d\n", + config->p2p_go_max_inactivity); + if (config->auto_interworking) + fprintf(f, "auto_interworking=%d\n", + config->auto_interworking); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 0863607..ff97379 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -141,6 +141,14 @@ struct wpa_ssid { char *passphrase; /** + * ext_psk - PSK/passphrase name in external storage + * + * If this is set, PSK/passphrase will be fetched from external storage + * when requesting association with the network. + */ + char *ext_psk; + + /** * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_* */ int pairwise_cipher; @@ -356,6 +364,8 @@ struct wpa_ssid { */ int frequency; + int ht40; + /** * wpa_ptk_rekey - Maximum lifetime for PTK in seconds * @@ -421,6 +431,10 @@ struct wpa_ssid { */ size_t num_p2p_clients; +#ifndef P2P_MAX_STORED_CLIENTS +#define P2P_MAX_STORED_CLIENTS 100 +#endif /* P2P_MAX_STORED_CLIENTS */ + /** * p2p_group - Network generated as a P2P group (used internally) */ @@ -512,6 +526,16 @@ struct wpa_ssid { * By default: 2 */ int dtim_period; + + /** + * auth_failures - Number of consecutive authentication failures + */ + unsigned int auth_failures; + + /** + * disabled_until - Network block disabled until this time if non-zero + */ + struct os_time disabled_until; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index de2ec58..6d9876c 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -344,13 +344,6 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw, wpa_config_update_psk(ssid); } - if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) { - wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, " - "but no PSK configured for network '" TSTR "'.", - netw); - errors++; - } - if ((ssid->group_cipher & WPA_CIPHER_CCMP) && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 041685a..059c586 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12,6 +12,7 @@ #include "utils/eloop.h" #include "common/version.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "eap_peer/eap.h" #include "eapol_supp/eapol_supp_sm.h" @@ -29,6 +30,7 @@ #include "p2p_supplicant.h" #include "p2p/p2p.h" #include "hs20_supplicant.h" +#include "wifi_display.h" #include "notify.h" #include "bss.h" #include "scan.h" @@ -98,6 +100,9 @@ static int pno_start(struct wpa_supplicant *wpa_s) ssid = ssid->next; } + if (wpa_s->conf->filter_rssi) + params.filter_rssi = wpa_s->conf->filter_rssi; + ret = wpa_drv_sched_scan(wpa_s, ¶ms, 10 * 1000); os_free(params.filter_ssids); if (ret == 0) @@ -130,7 +135,7 @@ static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) os_free(filter); return -1; } - n = os_realloc(filter, (count + 1) * ETH_ALEN); + n = os_realloc_array(filter, count + 1, ETH_ALEN); if (n == NULL) { os_free(filter); return -1; @@ -280,6 +285,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } } else if (os_strcasecmp(cmd, "ps") == 0) { ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1); +#ifdef CONFIG_WIFI_DISPLAY + } else if (os_strcasecmp(cmd, "wifi_display") == 0) { + wifi_display_enable(wpa_s->global, !!atoi(value)); +#endif /* CONFIG_WIFI_DISPLAY */ } else if (os_strcasecmp(cmd, "bssid_filter") == 0) { ret = set_bssid_filter(wpa_s, value); } else { @@ -307,6 +316,14 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, res = os_snprintf(buf, buflen, "%c%c", wpa_s->conf->country[0], wpa_s->conf->country[1]); +#ifdef CONFIG_WIFI_DISPLAY + } else if (os_strcasecmp(cmd, "wifi_display") == 0) { + res = os_snprintf(buf, buflen, "%d", + wpa_s->global->wifi_display); + if (res < 0 || (unsigned int) res >= buflen) + return -1; + return res; +#endif /* CONFIG_WIFI_DISPLAY */ } if (res < 0 || (unsigned int) res >= buflen) @@ -1121,7 +1138,9 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, #ifdef CONFIG_HS20 if (wpa_s->current_bss && - wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE)) { + wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) && + wpa_s->wpa_proto == WPA_PROTO_RSN && + wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { ret = os_snprintf(pos, end - pos, "hs20=1\n"); if (ret < 0 || ret >= end - pos) return pos - buf; @@ -1377,10 +1396,12 @@ static int wpa_supplicant_ctrl_iface_list_networks( if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; - ret = os_snprintf(pos, end - pos, "\t%s%s%s", + ret = os_snprintf(pos, end - pos, "\t%s%s%s%s", ssid == wpa_s->current_ssid ? "[CURRENT]" : "", ssid->disabled ? "[DISABLED]" : "", + ssid->disabled_until.sec ? + "[TEMP-DISABLED]" : "", ssid->disabled == 2 ? "[P2P-PERSISTENT]" : ""); if (ret < 0 || ret >= end - pos) @@ -1441,6 +1462,13 @@ static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) pos += ret; first = 0; } + if (cipher & WPA_CIPHER_GCMP) { + ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } return pos; } @@ -1640,7 +1668,7 @@ static int wpa_supplicant_ctrl_iface_scan_result( pos += ret; } #ifdef CONFIG_HS20 - if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { + if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) { ret = os_snprintf(pos, end - pos, "[HS20]"); if (ret < 0 || ret >= end - pos) return -1; @@ -2163,6 +2191,14 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict, first = 0; } + if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) { + ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); if (ret < 0 || ret >= end - pos) @@ -2211,6 +2247,14 @@ static int ctrl_iface_get_capability_group(int res, char *strict, first = 0; } + if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) { + ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); if (ret < 0 || ret >= end - pos) @@ -2406,7 +2450,7 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s, hmode = "A"; break; default: - return pos - buf; + continue; } ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode); if (ret < 0 || ret >= end - pos) @@ -2414,6 +2458,8 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s, pos += ret; chnl = wpa_s->hw.modes[j].channels; for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { + if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) + continue; ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan); if (ret < 0 || ret >= end - pos) return pos - buf; @@ -2715,6 +2761,31 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } #endif /* CONFIG_P2P */ +#ifdef CONFIG_WIFI_DISPLAY + if (mask & WPA_BSS_MASK_WIFI_DISPLAY) { + struct wpabuf *wfd; + ie = (const u8 *) (bss + 1); + wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len, + WFD_IE_VENDOR_TYPE); + if (wfd) { + ret = os_snprintf(pos, end - pos, "wfd_subelems="); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + pos += wpa_snprintf_hex(pos, end - pos, + wpabuf_head(wfd), + wpabuf_len(wfd)); + wpabuf_free(wfd); + + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + } +#endif /* CONFIG_WIFI_DISPLAY */ + #ifdef CONFIG_INTERWORKING if (mask & WPA_BSS_MASK_INTERNETW) { pos = anqp_add_hex(pos, end, "anqp_venue_name", @@ -2991,6 +3062,7 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; u8 dev_id[ETH_ALEN], *_dev_id = NULL; char *pos; + unsigned int search_delay; if (os_strstr(cmd, "type=social")) type = P2P_FIND_ONLY_SOCIAL; @@ -3005,7 +3077,15 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) _dev_id = dev_id; } - return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id); + pos = os_strstr(cmd, "delay="); + if (pos) { + pos += 6; + search_delay = atoi(pos); + } else + search_delay = wpas_p2p_search_delay(wpa_s); + + return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id, + search_delay); } @@ -3025,10 +3105,12 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, int go_intent = -1; int freq = 0; int pd; + int ht40; /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] * [persistent|persistent=<network id>] - * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */ + * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] + * [ht40] */ if (hwaddr_aton(cmd, addr)) return -1; @@ -3056,6 +3138,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, auth = os_strstr(pos, " auth") != NULL; automatic = os_strstr(pos, " auto") != NULL; pd = os_strstr(pos, " provdisc") != NULL; + ht40 = os_strstr(pos, " ht40") != NULL; pos2 = os_strstr(pos, " go_intent="); if (pos2) { @@ -3095,7 +3178,8 @@ 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); + auth, go_intent, freq, persistent_id, pd, + ht40); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; @@ -3195,6 +3279,10 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd, return -1; pos++; ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); +#ifdef CONFIG_WIFI_DISPLAY + } else if (os_strncmp(pos, "wifi-display ", 13) == 0) { + ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13); +#endif /* CONFIG_WIFI_DISPLAY */ } else { len = os_strlen(pos); if (len & 1) @@ -3517,7 +3605,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, - char *cmd, int freq) + char *cmd, int freq, int ht40) { int id; struct wpa_ssid *ssid; @@ -3531,26 +3619,31 @@ 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); + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40); } static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) { - int freq = 0; + int freq = 0, ht40; char *pos; pos = os_strstr(cmd, "freq="); if (pos) freq = atoi(pos + 5); + ht40 = os_strstr(cmd, "ht40") != NULL; + if (os_strncmp(cmd, "persistent=", 11) == 0) - return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq); + return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq, + ht40); if (os_strcmp(cmd, "persistent") == 0 || os_strncmp(cmd, "persistent ", 11) == 0) - return wpas_p2p_group_add(wpa_s, 1, freq); + return wpas_p2p_group_add(wpa_s, 1, freq, ht40); if (os_strncmp(cmd, "freq=", 5) == 0) - return wpas_p2p_group_add(wpa_s, 0, freq); + return wpas_p2p_group_add(wpa_s, 0, freq, ht40); + if (ht40) + return wpas_p2p_group_add(wpa_s, 0, freq, ht40); wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'", cmd); @@ -3653,8 +3746,8 @@ static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s, */ pos = param; while (pos && pos[0]) { - n = os_realloc(freq, - (count + 1) * sizeof(struct wpa_freq_range)); + n = os_realloc_array(freq, count + 1, + sizeof(struct wpa_freq_range)); if (n == NULL) { os_free(freq); return -1; @@ -3957,6 +4050,122 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) return anqp_send_req(wpa_s, dst_addr, id, num_id); } + + +static int gas_request(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 dst_addr[ETH_ALEN]; + struct wpabuf *advproto, *query = NULL; + int used, ret = -1; + char *pos, *end; + size_t len; + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + + pos = cmd + used; + while (*pos == ' ') + pos++; + + /* Advertisement Protocol ID */ + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + if (len & 0x01) + return -1; + len /= 2; + if (len == 0) + return -1; + advproto = wpabuf_alloc(len); + if (advproto == NULL) + return -1; + if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0) + goto fail; + + if (end) { + /* Optional Query Request */ + pos = end + 1; + while (*pos == ' ') + pos++; + + len = os_strlen(pos); + if (len) { + if (len & 0x01) + goto fail; + len /= 2; + if (len == 0) + goto fail; + query = wpabuf_alloc(len); + if (query == NULL) + goto fail; + if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0) + goto fail; + } + } + + ret = gas_send_request(wpa_s, dst_addr, advproto, query); + +fail: + wpabuf_free(advproto); + wpabuf_free(query); + + return ret; +} + + +static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, + size_t buflen) +{ + u8 addr[ETH_ALEN]; + int dialog_token; + int used; + char *pos; + size_t resp_len, start, requested_len; + + if (!wpa_s->last_gas_resp) + return -1; + + used = hwaddr_aton2(cmd, addr); + if (used < 0) + return -1; + + pos = cmd + used; + while (*pos == ' ') + pos++; + dialog_token = atoi(pos); + + if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 || + dialog_token != wpa_s->last_gas_dialog_token) + return -1; + + resp_len = wpabuf_len(wpa_s->last_gas_resp); + start = 0; + requested_len = resp_len; + + pos = os_strchr(pos, ' '); + if (pos) { + start = atoi(pos); + if (start > resp_len) + return os_snprintf(buf, buflen, "FAIL-Invalid range"); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + requested_len = atoi(pos); + if (start + requested_len > resp_len) + return os_snprintf(buf, buflen, "FAIL-Invalid range"); + } + + if (requested_len * 2 + 1 > buflen) + return os_snprintf(buf, buflen, "FAIL-Too long response"); + + return wpa_snprintf_hex(buf, buflen, + wpabuf_head_u8(wpa_s->last_gas_resp) + start, + requested_len); +} #endif /* CONFIG_INTERWORKING */ @@ -4185,6 +4394,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (os_strcmp(buf, "PING") == 0) { os_memcpy(reply, "PONG\n", 5); reply_len = 5; + } else if (os_strcmp(buf, "IFNAME") == 0) { + reply_len = os_strlen(wpa_s->ifname); + os_memcpy(reply, wpa_s->ifname, reply_len); } else if (os_strncmp(buf, "RELOG", 5) == 0) { if (wpa_debug_reopen_file() < 0) reply_len = -1; @@ -4375,7 +4587,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_p2p_group_remove(wpa_s, buf + 17)) reply_len = -1; } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { - if (wpas_p2p_group_add(wpa_s, 0, 0)) + if (wpas_p2p_group_add(wpa_s, 0, 0, 0)) reply_len = -1; } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { if (p2p_ctrl_group_add(wpa_s, buf + 14)) @@ -4447,6 +4659,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (p2p_ctrl_ext_listen(wpa_s, "") < 0) reply_len = -1; #endif /* CONFIG_P2P */ +#ifdef CONFIG_WIFI_DISPLAY + } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { + if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) { + reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16, + reply, reply_size); +#endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING } else if (os_strcmp(buf, "FETCH_ANQP") == 0) { if (interworking_fetch_anqp(wpa_s) < 0) @@ -4463,6 +4683,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) { if (get_anqp(wpa_s, buf + 9) < 0) reply_len = -1; + } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) { + if (gas_request(wpa_s, buf + 12) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) { + reply_len = gas_response_get(wpa_s, buf + 17, reply, + reply_size); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) { diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index c831e6c..994f9b1 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -163,6 +163,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, perror("recvfrom(ctrl_iface)"); return; } + +#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { /* * The OS networking stack is expected to drop this kind of @@ -174,6 +176,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, "source %s", inet_ntoa(from.sin_addr)); return; } +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ + buf[res] = '\0'; if (os_strcmp(buf, "GET_COOKIE") == 0) { @@ -266,6 +270,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { struct ctrl_iface_priv *priv; struct sockaddr_in addr; + int port = WPA_CTRL_IFACE_PORT; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) @@ -285,13 +290,25 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) os_memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + addr.sin_addr.s_addr = INADDR_ANY; +#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ addr.sin_addr.s_addr = htonl((127 << 24) | 1); - addr.sin_port = htons(WPA_CTRL_IFACE_PORT); +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +try_again: + addr.sin_port = htons(port); if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + port--; + if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT) + goto try_again; perror("bind(AF_INET)"); 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 */ + eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv); wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); @@ -442,6 +459,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, perror("recvfrom(ctrl_iface)"); return; } + +#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { /* * The OS networking stack is expected to drop this kind of @@ -453,6 +472,8 @@ 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_REMOTE */ + buf[res] = '\0'; if (os_strcmp(buf, "GET_COOKIE") == 0) { @@ -502,6 +523,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) { struct ctrl_iface_global_priv *priv; struct sockaddr_in addr; + int port = WPA_GLOBAL_CTRL_IFACE_PORT; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) @@ -523,13 +545,26 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) os_memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + addr.sin_addr.s_addr = INADDR_ANY; +#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ addr.sin_addr.s_addr = htonl((127 << 24) | 1); - addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT); +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +try_again: + addr.sin_port = htons(port); if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + port++; + if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) < + WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT) + goto try_again; perror("bind(AF_INET)"); goto fail; } +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port); +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ + eloop_register_read_sock(priv->sock, wpa_supplicant_global_ctrl_iface_receive, global, priv); diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 67a0a8b..5d81b43 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -11,6 +11,8 @@ #include <sys/stat.h> #include <grp.h> #include <stddef.h> +#include <unistd.h> +#include <fcntl.h> #ifdef ANDROID #include <cutils/sockets.h> #endif /* ANDROID */ @@ -282,6 +284,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) char *buf, *dir = NULL, *gid_str = NULL; struct group *grp; char *endp; + int flags; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) @@ -428,6 +431,20 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) #ifdef ANDROID havesock: #endif /* ANDROID */ + + /* + * Make socket non-blocking so that we don't hang forever if + * target dies unexpectedly. + */ + flags = fcntl(priv->sock, F_GETFL); + if (flags >= 0) { + flags |= O_NONBLOCK; + if (fcntl(priv->sock, F_SETFL, flags) < 0) { + perror("fcntl(ctrl, O_NONBLOCK)"); + /* Not fatal, continue on.*/ + } + } + eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv); wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c index 67924e0..61a9430 100644 --- a/wpa_supplicant/dbus/dbus_dict_helpers.c +++ b/wpa_supplicant/dbus/dbus_dict_helpers.c @@ -738,7 +738,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( entry->bytearray_value = NULL; entry->array_type = DBUS_TYPE_BYTE; - buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE); + buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE); if (!buffer) return FALSE; @@ -748,8 +748,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( char byte; if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) { - nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE * - (count + BYTE_ARRAY_CHUNK_SIZE)); + nbuffer = os_realloc_array( + buffer, count + BYTE_ARRAY_CHUNK_SIZE, + BYTE_ARRAY_ITEM_SIZE); if (nbuffer == NULL) { os_free(buffer); wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_" @@ -795,7 +796,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( entry->strarray_value = NULL; entry->array_type = DBUS_TYPE_STRING; - buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE); + buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE); if (buffer == NULL) return FALSE; @@ -806,8 +807,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( char *str; if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) { - nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE * - (count + STR_ARRAY_CHUNK_SIZE)); + nbuffer = os_realloc_array( + buffer, count + STR_ARRAY_CHUNK_SIZE, + STR_ARRAY_ITEM_SIZE); if (nbuffer == NULL) { os_free(buffer); wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_" @@ -871,8 +873,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray( buflen += BIN_ARRAY_CHUNK_SIZE; - newbuf = os_realloc(entry->binarray_value, - buflen * BIN_ARRAY_ITEM_SIZE); + newbuf = os_realloc_array(entry->binarray_value, + buflen, BIN_ARRAY_ITEM_SIZE); if (!newbuf) goto cleanup; entry->binarray_value = newbuf; diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index a9957ab..4eeb93a 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -1104,7 +1104,6 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; - char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; iface = wpa_s->parent->global->dbus; @@ -1142,14 +1141,8 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, client ? "client" : "GO")) goto nomem; - os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, - "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", - wpa_s->parent->dbus_new_path, network_id); - if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object", group_obj_path) || - !wpa_dbus_dict_append_object_path(&dict_iter, "network_object", - net_obj_path) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) goto nomem; @@ -2391,6 +2384,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { END_ARGS } }, + { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_reassociate, + { + END_ARGS + } + }, { "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_remove_network, { diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 8145a70..5668e1a 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -609,6 +609,7 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, out: os_free(driver); os_free(ifname); + os_free(confname); os_free(bridge_ifname); return reply; @@ -870,7 +871,7 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) num++; - paths = os_zalloc(num * sizeof(char*)); + paths = os_calloc(num, sizeof(char *)); if (!paths) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; @@ -1158,8 +1159,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, #define FREQS_ALLOC_CHUNK 32 if (freqs_num % FREQS_ALLOC_CHUNK == 0) { - nfreqs = os_realloc(freqs, sizeof(int) * - (freqs_num + FREQS_ALLOC_CHUNK)); + nfreqs = os_realloc_array( + freqs, freqs_num + FREQS_ALLOC_CHUNK, + sizeof(int)); if (nfreqs == NULL) os_free(freqs); freqs = nfreqs; @@ -1179,8 +1181,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, dbus_message_iter_next(&array_iter); } - nfreqs = os_realloc(freqs, - sizeof(int) * (freqs_num + 1)); + nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int)); if (nfreqs == NULL) os_free(freqs); freqs = nfreqs; @@ -1404,6 +1405,33 @@ err: /** + * wpas_dbus_handler_reassociate - Reassociate to current AP + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NotConnected DBus error message if not connected + * or NULL otherwise. + * + * Handler function for "Reassociate" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->current_ssid != NULL) { + wpa_s->normal_scans = 0; + wpa_supplicant_reinit_autoscan(wpa_s); + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, + "This interface is not connected"); +} + + +/** * wpas_dbus_handler_remove_network - Remove a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface @@ -1901,6 +1929,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, goto nomem; } + if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp")) + goto nomem; + } + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "tkip")) @@ -1942,6 +1976,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, goto nomem; } + if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp")) + goto nomem; + } + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "tkip")) @@ -2430,7 +2470,7 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, void *user_data) { struct wpa_supplicant *wpa_s = user_data; - dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age; + dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &expire_count, error); @@ -2759,7 +2799,7 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, unsigned int i = 0; dbus_bool_t success = FALSE; - paths = os_zalloc(wpa_s->num_bss * sizeof(char *)); + paths = os_calloc(wpa_s->num_bss, sizeof(char *)); if (!paths) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; @@ -2822,7 +2862,7 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, if (!network_is_persistent_group(ssid)) num++; - paths = os_zalloc(num * sizeof(char *)); + paths = os_calloc(num, sizeof(char *)); if (!paths) { dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; @@ -3154,7 +3194,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, { DBusMessageIter iter_dict, variant_iter; const char *group; - const char *pairwise[2]; /* max 2 pairwise ciphers is supported */ + const char *pairwise[3]; /* max 3 pairwise ciphers is supported */ const char *key_mgmt[7]; /* max 7 key managements may be supported */ int n; @@ -3197,6 +3237,9 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, case WPA_CIPHER_CCMP: group = "ccmp"; break; + case WPA_CIPHER_GCMP: + group = "gcmp"; + break; case WPA_CIPHER_WEP104: group = "wep104"; break; @@ -3214,6 +3257,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, pairwise[n++] = "tkip"; if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) pairwise[n++] = "ccmp"; + if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) + pairwise[n++] = "gcmp"; if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", pairwise, n)) diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index cff218f..178a76b 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -94,6 +94,9 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, + struct wpa_supplicant *wpa_s); + DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index f4541f7..aee8b3a 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -127,7 +127,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, } wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types, - NULL); + NULL, 0); os_free(req_dev_types); return reply; @@ -346,13 +346,13 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, if (ssid == NULL || ssid->disabled != 2) goto inv_args; - if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) { + if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 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)) + } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0)) goto inv_args; out: @@ -504,7 +504,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); + go_intent, freq, -1, 0, 0); if (new_pin >= 0) { char npin[9]; @@ -1049,7 +1049,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, * Now construct the peer object paths in a form suitable for * array_property_getter helper below. */ - peer_obj_paths = os_zalloc(num * sizeof(char *)); + peer_obj_paths = os_calloc(num, sizeof(char *)); if (!peer_obj_paths) { out_of_mem = 1; @@ -1509,7 +1509,7 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, if (network_is_persistent_group(ssid)) num++; - paths = os_zalloc(num * sizeof(char *)); + paths = os_calloc(num, sizeof(char *)); if (!paths) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; @@ -1816,7 +1816,7 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, num_members = p2p_get_group_num_members(wpa_s->p2p_group); - paths = os_zalloc(num_members * sizeof(char *)); + paths = os_calloc(num_members, sizeof(char *)); if (!paths) goto out_of_memory; diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index fe1401f..711b407 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -232,6 +232,7 @@ CONFIG_SMARTCARD=y # unix = UNIX domain sockets (default for Linux/*BSD) # udp = UDP sockets using localhost (127.0.0.1) # named_pipe = Windows Named Pipe (default for Windows) +# udp-remote = UDP sockets with remote access (only for tests systems/purpose) # y = use default (backwards compatibility) # If this option is commented out, control interface is not included in the # build. @@ -505,10 +506,18 @@ CONFIG_PEERKEY=y # Autoscan # This can be used to enable automatic scan support in wpa_supplicant. -# See wpa_supplicant.conf for more information on autoscan usage. +#Â See wpa_supplicant.conf for more information on autoscan usage. # # Enabling directly a module will enable autoscan support. # For exponential module: #CONFIG_AUTOSCAN_EXPONENTIAL=y # For periodic module: #CONFIG_AUTOSCAN_PERIODIC=y + +# Password (and passphrase, etc.) backend for external storage +# These optional mechanisms can be used to add support for storing passwords +# and other secrets in external (to wpa_supplicant) location. This allows, for +# example, operating system specific key storage to be used +# +# External password backend for testing purposes (developer use) +#CONFIG_EXT_PASSWORD_TEST=y diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 82a7bcb..ee9f6b0 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -698,4 +698,14 @@ static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s, return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq); } +static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s, + enum wnm_oper oper, const u8 *peer, + u8 *buf, u16 *buf_len) +{ + if (!wpa_s->driver->wnm_oper) + return -1; + return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf, + buf_len); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c index c220aec..d1eb4ff 100644 --- a/wpa_supplicant/eap_register.c +++ b/wpa_supplicant/eap_register.c @@ -35,6 +35,11 @@ int eap_register_methods(void) ret = eap_peer_tls_register(); #endif /* EAP_TLS */ +#ifdef EAP_UNAUTH_TLS + if (ret == 0) + ret = eap_peer_unauth_tls_register(); +#endif /* EAP_UNAUTH_TLS */ + #ifdef EAP_MSCHAPv2 if (ret == 0) ret = eap_peer_mschapv2_register(); @@ -145,6 +150,11 @@ int eap_register_methods(void) ret = eap_server_tls_register(); #endif /* EAP_SERVER_TLS */ +#ifdef EAP_SERVER_UNAUTH_TLS + if (ret == 0) + ret = eap_server_unauth_tls_register(); +#endif /* EAP_SERVER_UNAUTH_TLS */ + #ifdef EAP_SERVER_MSCHAPV2 if (ret == 0) ret = eap_server_mschapv2_register(); diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index e53e156..7d63c1b 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -13,6 +13,7 @@ #include <assert.h> #include "common.h" +#include "utils/ext_password.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "eap_peer/eap.h" @@ -55,9 +56,8 @@ struct eapol_test_data { struct radius_client_data *radius; struct hostapd_radius_servers *radius_conf; - u8 *last_eap_radius; /* last received EAP Response from Authentication - * Server */ - size_t last_eap_radius_len; + /* last received EAP Response from Authentication Server */ + struct wpabuf *last_eap_radius; u8 authenticator_pmk[PMK_LEN]; size_t authenticator_pmk_len; @@ -488,7 +488,7 @@ static void test_eapol_clean(struct eapol_test_data *e, struct extra_radius_attr *p, *prev; radius_client_deinit(e->radius); - os_free(e->last_eap_radius); + wpabuf_free(e->last_eap_radius); radius_msg_free(e->last_recv_radius); e->last_recv_radius = NULL; os_free(e->eap_identity); @@ -506,6 +506,10 @@ static void test_eapol_clean(struct eapol_test_data *e, wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); wpa_s->ctrl_iface = NULL; } + + ext_password_deinit(wpa_s->ext_pw); + wpa_s->ext_pw = NULL; + wpa_config_free(wpa_s->conf); p = e->extra_attrs; @@ -574,9 +578,8 @@ static char *eap_type_text(u8 type) static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) { - u8 *eap; - size_t len; - struct eap_hdr *hdr; + struct wpabuf *eap; + const struct eap_hdr *hdr; int eap_type = -1; char buf[64]; struct radius_msg *msg; @@ -586,30 +589,29 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) msg = e->last_recv_radius; - eap = radius_msg_get_eap(msg, &len); + eap = radius_msg_get_eap(msg); if (eap == NULL) { /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ wpa_printf(MSG_DEBUG, "could not extract " "EAP-Message from RADIUS message"); - os_free(e->last_eap_radius); + wpabuf_free(e->last_eap_radius); e->last_eap_radius = NULL; - e->last_eap_radius_len = 0; return; } - if (len < sizeof(*hdr)) { + if (wpabuf_len(eap) < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "too short EAP packet " "received from authentication server"); - os_free(eap); + wpabuf_free(eap); return; } - if (len > sizeof(*hdr)) - eap_type = eap[sizeof(*hdr)]; + if (wpabuf_len(eap) > sizeof(*hdr)) + eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; - hdr = (struct eap_hdr *) eap; + hdr = wpabuf_head(eap); switch (hdr->code) { case EAP_CODE_REQUEST: os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", @@ -632,7 +634,7 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) break; default: os_strlcpy(buf, "unknown EAP code", sizeof(buf)); - wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len); + wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap); break; } wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " @@ -641,20 +643,21 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ - os_free(e->last_eap_radius); + wpabuf_free(e->last_eap_radius); e->last_eap_radius = eap; - e->last_eap_radius_len = len; { struct ieee802_1x_hdr *dot1x; - dot1x = os_malloc(sizeof(*dot1x) + len); + dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap)); assert(dot1x != NULL); dot1x->version = EAPOL_VERSION; dot1x->type = IEEE802_1X_TYPE_EAP_PACKET; - dot1x->length = htons(len); - os_memcpy((u8 *) (dot1x + 1), eap, len); + dot1x->length = htons(wpabuf_len(eap)); + os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap), + wpabuf_len(eap)); eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, - (u8 *) dot1x, sizeof(*dot1x) + len); + (u8 *) dot1x, + sizeof(*dot1x) + wpabuf_len(eap)); os_free(dot1x); } } @@ -1228,6 +1231,9 @@ int main(int argc, char *argv[]) if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid)) return -1; + if (wpas_init_ext_pw(&wpa_s) < 0) + return -1; + if (wait_for_monitor) wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 451bfd4..a610008 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -23,6 +23,7 @@ #include "eap_peer/eap.h" #include "ap/hostapd.h" #include "p2p/p2p.h" +#include "wnm_sta.h" #include "notify.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -40,11 +41,31 @@ #include "bss.h" #include "scan.h" #include "offchannel.h" +#include "interworking.h" + + +static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct os_time now; + + if (ssid == NULL || ssid->disabled_until.sec == 0) + return 0; + + os_get_time(&now); + if (ssid->disabled_until.sec > now.sec) + return ssid->disabled_until.sec - now.sec; + + wpas_clear_temp_disabled(wpa_s, ssid, 0); + + return 0; +} static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid, *old_ssid; + int res; if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) return 0; @@ -63,6 +84,13 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) return -1; } + res = wpas_temp_disabled(wpa_s, ssid); + if (res > 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily " + "disabled for %d second(s)", res); + return -1; + } + wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the " "current AP"); if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { @@ -148,6 +176,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); wpa_s->ap_ies_from_associnfo = 0; + wpa_s->current_ssid = NULL; + wpa_s->key_mgmt = 0; } @@ -450,6 +480,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 1; } + if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie && + !rsn_ie) { + wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X"); + return 1; + } + if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match"); @@ -648,12 +684,20 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, for (ssid = group; ssid; ssid = ssid->pnext) { int check_ssid = wpa ? 1 : (ssid->ssid_len != 0); + int res; if (wpas_network_disabled(wpa_s, ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled"); continue; } + res = wpas_temp_disabled(wpa_s, ssid); + if (res > 0) { + wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled " + "temporarily for %d second(s)", res); + continue; + } + #ifdef CONFIG_WPS if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted " @@ -1032,7 +1076,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, #else if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && #endif - wpa_s->global->p2p != NULL) { + wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending) { wpa_s->p2p_cb_on_scan_complete = 0; if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " @@ -1040,6 +1084,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return -1; } } + wpa_s->sta_scan_pending = 0; #endif /* CONFIG_P2P */ scan_res = wpa_supplicant_get_scan_results(wpa_s, @@ -1134,6 +1179,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return 0; } + wpas_wps_update_ap_info(wpa_s, scan_res); + selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid); if (selected) { @@ -1178,6 +1225,19 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return 0; } #endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + if (wpa_s->conf->auto_interworking && + wpa_s->conf->interworking && + wpa_s->conf->cred) { + wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: " + "start ANQP fetch since no matching " + "networks found"); + wpa_s->network_select = 1; + wpa_s->auto_network_select = 1; + interworking_start_fetch_anqp(wpa_s); + return 0; + } +#endif /* CONFIG_INTERWORKING */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); @@ -1548,7 +1608,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, { u8 bssid[ETH_ALEN]; int ft_completed; - int bssid_changed; struct wpa_driver_capa capa; #ifdef CONFIG_AP @@ -1566,17 +1625,21 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) return; + if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { + wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID"); + wpa_supplicant_disassociate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + return; + } + wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); - if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 && - os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { + if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID=" MACSTR, MAC2STR(bssid)); random_add_randomness(bssid, ETH_ALEN); - bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN); os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); - if (bssid_changed) - wpas_notify_bssid_changed(wpa_s); + wpas_notify_bssid_changed(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) { wpa_clear_keys(wpa_s, bssid); @@ -1728,6 +1791,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk); } #endif /* CONFIG_IBSS_RSN */ + + wpas_wps_notify_assoc(wpa_s, bssid); } @@ -1767,6 +1832,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " "pre-shared key may be incorrect"); + wpas_auth_failed(wpa_s); } if (!wpa_s->auto_reconnect_disabled || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) { @@ -2037,6 +2103,25 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s, #endif /* CONFIG_TDLS */ +#ifdef CONFIG_IEEE80211V +static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (data == NULL) + return; + switch (data->wnm.oper) { + case WNM_OPER_SLEEP: + wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request " + "(action=%d, intval=%d)", + data->wnm.sleep_action, data->wnm.sleep_intval); + ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action, + data->wnm.sleep_intval); + break; + } +} +#endif /* CONFIG_IEEE80211V */ + + #ifdef CONFIG_IEEE80211R static void wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s, @@ -2323,6 +2408,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated); + if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED || + ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || + (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) && + eapol_sm_failed(wpa_s->eapol))) + wpas_auth_failed(wpa_s); #ifdef CONFIG_P2P if (event == EVENT_DEAUTH && data) { wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr, @@ -2339,6 +2429,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #ifndef CONFIG_NO_SCAN_PROCESSING case EVENT_SCAN_RESULTS: wpa_supplicant_event_scan_results(wpa_s, data); +#ifdef CONFIG_P2P + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL && + wpa_s->wpa_state != WPA_AUTHENTICATING && + wpa_s->wpa_state != WPA_ASSOCIATING) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after scan result processing"); + } + } +#endif /* CONFIG_P2P */ break; #endif /* CONFIG_NO_SCAN_PROCESSING */ case EVENT_ASSOCINFO: @@ -2360,6 +2462,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_supplicant_event_tdls(wpa_s, data); break; #endif /* CONFIG_TDLS */ +#ifdef CONFIG_IEEE80211V + case EVENT_WNM: + wpa_supplicant_event_wnm(wpa_s, data); + break; +#endif /* CONFIG_IEEE80211V */ #ifdef CONFIG_IEEE80211R case EVENT_FT_RESPONSE: wpa_supplicant_event_ft_response(wpa_s, data); @@ -2585,6 +2692,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } #endif /* CONFIG_SME */ #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211V + if (data->rx_action.category == WLAN_ACTION_WNM) { + ieee802_11_rx_wnm_action(wpa_s, &data->rx_action); + break; + } +#endif /* CONFIG_IEEE80211V */ #ifdef CONFIG_GAS if (data->rx_action.category == WLAN_ACTION_PUBLIC && gas_query_rx(wpa_s->gas, data->rx_action.da, diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py new file mode 100644 index 0000000..59b0a9d --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_connect.py @@ -0,0 +1,299 @@ +#!/usr/bin/python +# Tests p2p_connect +# Will try to connect to another peer +# and form a group +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import getopt +from dbus.mainloop.glib import DBusGMainLoop + + +def usage(): + print "Usage:" + print " %s -i <interface_name> -m <wps_method> \ " \ + % sys.argv[0] + print " -a <addr> [-p <pin>] [-g <go_intent>] \ " + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -m = wps method" + print " -a = peer address" + print " -p = pin number (8 digits)" + print " -g = group owner intent" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0] + + +# Required Signals +def GONegotiationSuccess(status): + print "Go Negotiation Success" + +def GONegotiationFailure(status): + print 'Go Negotiation Failed. Status:' + print format(status) + os._exit(0) + +def GroupStarted(properties): + if properties.has_key("group_object"): + print 'Group Formation Complete %s' \ + % properties["group_object"] + os._exit(0) + +def WpsFailure(status, etc): + print "WPS Authentication Failure".format(status) + print etc + os._exit(0) + +class P2P_Connect(): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global ifname + global wpas + global wpas_dbus_interface + global timeout + global path + global wps_method + global go_intent + global addr + global pin + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Dictionary of Arguements + global p2p_connect_arguements + + # Constructor + def __init__(self,ifname,wpas_dbus_interface,addr, + pin,wps_method,go_intent): + # Initializes variables and threads + self.ifname = ifname + self.wpas_dbus_interface = wpas_dbus_interface + self.wps_method = wps_method + self.go_intent = go_intent + self.addr = addr + self.pin = pin + + # Generating interface/object paths + self.wpas_dbus_opath = \ + "/" + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = \ + self.wpas_dbus_opath + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface( + self.wpas_object, self.wpas_dbus_interface) + + # See if wpa_supplicant already knows about this interface + self.path = None + try: + self.path = self.wpas.GetInterface(ifname) + except: + if not str(exc).startswith( + self.wpas_dbus_interface + \ + ".InterfaceUnknown:"): + raise exc + try: + path = self.wpas.CreateInterface( + {'Ifname': ifname, 'Driver': 'test'}) + time.sleep(1) + + except dbus.DBusException, exc: + if not str(exc).startswith( + self.wpas_dbus_interface + \ + ".InterfaceExists:"): + raise exc + + # Get Interface and objects + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface,self.path) + self.p2p_interface = dbus.Interface( + self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Add signals + self.bus.add_signal_receiver(GONegotiationSuccess, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GONegotiationSuccess") + self.bus.add_signal_receiver(GONegotiationFailure, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GONegotiationFailure") + self.bus.add_signal_receiver(GroupStarted, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GroupStarted") + self.bus.add_signal_receiver(WpsFailure, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="WpsFailed") + + + #Constructing all the arguements needed to connect + def constructArguements(self): + # Adding required arguements + self.p2p_connect_arguements = {'wps_method':self.wps_method, + 'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)} + + # Display requires a pin, and a go intent of 15 + if (self.wps_method == 'display'): + if (self.pin != None): + self.p2p_connect_arguements.update({'pin':self.pin}) + else: + print "Error:\n Pin required for wps_method=display" + usage() + quit() + + if (self.go_intent != None and int(self.go_intent) != 15): + print "go_intent overwritten to 15" + + self.go_intent = '15' + + # Keypad requires a pin, and a go intent of less than 15 + elif (self.wps_method == 'keypad'): + if (self.pin != None): + self.p2p_connect_arguements.update({'pin':self.pin}) + else: + print "Error:\n Pin required for wps_method=keypad" + usage() + quit() + + if (self.go_intent != None and int(self.go_intent) == 15): + error = "Error :\n Group Owner intent cannot be" + \ + " 15 for wps_method=keypad" + print error + usage() + quit() + + # Doesn't require pin + # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad + elif (self.wps_method == 'pin'): + if (self.pin != None): + print "pin ignored" + + # No pin is required for pbc so it is ignored + elif (self.wps_method == 'pbc'): + if (self.pin != None): + print "pin ignored" + + else: + print "Error:\n wps_method not supported or does not exist" + usage() + quit() + + # Go_intent is optional for all arguements + if (self.go_intent != None): + self.p2p_connect_arguements.update( + {'go_intent':dbus.Int32(self.go_intent)}) + + # Running p2p_connect + def run(self): + try: + result_pin = self.p2p_interface.Connect( + self.p2p_connect_arguements) + + except dbus.DBusException, exc: + raise exc + + if (self.wps_method == 'pin' and \ + not self.p2p_connect_arguements.has_key('pin') ): + print "Connect return with pin value of %d " % int(result_pin) + gobject.MainLoop().run() + +if __name__ == "__main__": + + # Required + interface_name = None + wps_method = None + addr = None + + # Conditionally optional + pin = None + + # Optional + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + go_intent = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:m:a:p:g:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # WPS Method + elif (key == "-m"): + wps_method = value + # Address + elif (key == "-a"): + addr = value + # Pin + elif (key == "-p"): + pin = value + # Group Owner Intent + elif (key == "-g"): + go_intent = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Required Arguements check + if (interface_name == None or wps_method == None or addr == None): + print "Error:\n Required arguements not specified" + usage() + quit() + + # Group Owner Intent Check + if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ): + print "Error:\n Group Owner Intent must be between 0 and 15 inclusive" + usage() + quit() + + # Pin Check + if (pin != None and len(pin) != 8): + print "Error:\n Pin is not 8 digits" + usage() + quit() + + try: + p2p_connect_test = P2P_Connect(interface_name,wpas_dbus_interface, + addr,pin,wps_method,go_intent) + + except: + print "Error:\n Invalid Arguements" + usage() + quit() + + p2p_connect_test.constructArguements() + p2p_connect_test.run() + + os._exit(0) diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py new file mode 100644 index 0000000..c3e39b3 --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_disconnect.py @@ -0,0 +1,169 @@ +#!/usr/bin/python +# Tests P2P_Disconnect +# Will perform disconnect on interface_name +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> \ " \ + % sys.argv[0] + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i p2p-wlan0-0" % sys.argv[0] + +# Required Signals +def GroupFinished(status, etc): + print "Disconnected" + os._exit(0) + +class P2P_Disconnect (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.timeout = timeout + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Signals + self.bus.add_signal_receiver(GroupFinished, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GroupFinished") + + # Runs p2p_disconnect + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + self.p2p_interface.Disconnect() + gobject.MainLoop().run() + + +if __name__ == "__main__": + + timeout = 5 + # Defaults for optional inputs + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + # Constructor + try: + p2p_disconnect_test = P2P_Disconnect(interface_name, + wpas_dbus_interface,timeout) + + except: + print "Error:\n Invalid wpas_dbus_interface" + usage() + quit() + + # Start P2P_Disconnect + p2p_disconnect_test.start() + + try: + time.sleep(int(p2p_disconnect_test.timeout)) + + except: + pass + + print "Disconnect timed out" + quit() diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py new file mode 100644 index 0000000..973d46a --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_find.py @@ -0,0 +1,192 @@ +#!/usr/bin/python +# Tests p2p_find +# Will list all devices found/lost within a time frame (timeout) +# Then Program will exit +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> [-t <timeout>] \ " \ + % sys.argv[0] + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -t = timeout = 0s (infinite)" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i wlan0 -t 10" % sys.argv[0] + +# Required Signals +def deviceFound(devicepath): + print "Device found: %s" % (devicepath) + +def deviceLost(devicepath): + print "Device lost: %s" % (devicepath) + +class P2P_Find (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global timeout + global path + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.timeout = int(timeout) + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + #Adds listeners for find and lost + self.bus.add_signal_receiver(deviceFound, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceFound") + self.bus.add_signal_receiver(deviceLost, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceLost") + + + # Sets up p2p_find + P2PFindDict = dbus.Dictionary( + {'Timeout':int(self.timeout)}) + self.p2p_interface.Find(P2PFindDict) + + # Run p2p_find + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + +if __name__ == "__main__": + + # Defaults for optional inputs + timeout = 0 + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:t:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Timeout + elif (key == "-t"): + if ( int(value) >= 0): + timeout = value + else: + print "Error:\n Timeout cannot be negative" + usage() + quit() + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + # Constructor + try: + p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout) + + except: + print "Error:\n Invalid wpas_dbus_interface" + usage() + quit() + + # Start P2P_Find + p2p_find_test.start() + + try: + # If timeout is 0, then run forever + if (timeout == 0): + while(True): + pass + # Else sleep for (timeout) + else: + time.sleep(p2p_find_test.timeout) + + except: + pass + + quit() diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py new file mode 100644 index 0000000..ff8509d --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_flush.py @@ -0,0 +1,168 @@ +#!/usr/bin/python +# Tests P2P_Flush +# Will flush the p2p interface +# Then Program will exit +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> \ " \ + % sys.argv[0] + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i wlan0" % sys.argv[0] + +# Required Signals\ +def deviceLost(devicepath): + print "Device lost: %s" % (devicepath) + +class P2P_Flush (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.timeout = timeout + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Signals + self.bus.add_signal_receiver(deviceLost, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceLost") + + # Runs p2p_flush + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + self.p2p_interface.Flush() + gobject.MainLoop().run() + + +if __name__ == "__main__": + # Needed to show which devices were lost + timeout = 5 + # Defaults for optional inputs + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + # Constructor + try: + p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout) + + except: + print "Error:\n Invalid wpas_dbus_interface" + usage() + quit() + + # Start P2P_Find + p2p_flush_test.start() + + try: + time.sleep(int(p2p_flush_test.timeout)) + + except: + pass + + print "p2p_flush complete" + quit() diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py new file mode 100644 index 0000000..5c8fdaf --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_group_add.py @@ -0,0 +1,222 @@ +#!/usr/bin/python +# Tests p2p_group_add +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import getopt +import threading +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> [-p <persistent>] \ " \ + % sys.argv[0] + print " [-f <frequency>] [-o <group_object_path>] \ " + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -p = persistant group = 0 (0=false, 1=true)" + print " -f = frequency" + print " -o = persistent group object path" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i wlan0" % sys.argv[0] + +# Required Signals +def GroupStarted(properties): + if properties.has_key("group_object"): + print 'Group Formation Complete %s' \ + % properties["group_object"] + os._exit(0) + +def WpsFailure(status, etc): + print "WPS Authentication Failure".format(status) + print etc + os._exit(0) + +class P2P_Group_Add (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global persistent + global frequency + global persistent_group_object + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Arguements + global P2PDictionary + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,persistent,frequency, + persistent_group_object): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.persistent = persistent + self.frequency = frequency + self.persistent_group_object = persistent_group_object + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + #Adds listeners + self.bus.add_signal_receiver(GroupStarted, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GroupStarted") + self.bus.add_signal_receiver(WpsFailure, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="WpsFailed") + + # Sets up p2p_group_add dictionary + def constructArguements(self): + self.P2PDictionary = {'persistent':self.persistent} + + if (self.frequency != None): + if (int(self.frequency) > 0): + self.P2PDictionary.update({'frequency':int(self.frequency)}) + else: + print "Error:\n Frequency must be greater than 0" + usage() + os._exit(0) + + if (self.persistent_group_object != None): + self.P2PDictionary.update({'persistent_group_object': + self.persistent_group_object}) + + # Run p2p_group_remove + def run(self): + try: + self.p2p_interface.GroupAdd(self.P2PDictionary) + + except: + print "Error:\n Could not preform group add" + usage() + os._exit(0) + + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + + +if __name__ == "__main__": + + # Defaults for optional inputs + # 0 = false, 1 = true + persistent = False + frequency = None + persistent_group_object = None + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:p:f:o:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Timeout + elif (key == "-p"): + if (value == '0'): + persistent = False + elif (value == '1'): + persistent = True + else: + print "Error:\n Persistent can only be 1 or 0" + usage() + os._exit(0) + # Frequency + elif (key == "-f"): + frequency = value + # Persistent group object path + elif (key == "-o"): + persistent_group_object = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + try: + p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface, + persistent,frequency,persistent_group_object) + except: + print "Error:\n Invalid Arguements" + + p2p_group_add_test.constructArguements() + p2p_group_add_test.start() + time.sleep(5) + print "Error:\n Group formation timed out" + os._exit(0) diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py new file mode 100644 index 0000000..6deb397 --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_invite.py @@ -0,0 +1,201 @@ +#!/usr/bin/python +# Tests p2p_invite +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import getopt +import threading +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> -a <addr> \ " \ + % sys.argv[0] + print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -a = address of peer" + print " -o = persistent group object path" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0] + +# Required Signals +def InvitationResult(invite_result): + print "Inviation Result signal :" + status = invite_result['status'] + print "status = ", status + if invite_result.has_key('BSSID'): + bssid = invite_result['BSSID'] + print "BSSID = ", hex(bssid[0]) , ":" , \ + hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \ + hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \ + hex(bssid[5]) + os._exit(0) + +class P2P_Invite (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global addr + global persistent_group_object + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Arguements + global P2PDictionary + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,addr, + persistent_group_object): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.addr = addr + self.persistent_group_object = persistent_group_object + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + #Adds listeners + self.bus.add_signal_receiver(InvitationResult, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="InvitationResult") + + # Sets up p2p_invite dictionary + def constructArguements(self): + self.P2PDictionary = \ + {'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)} + if (self.persistent_group_object != None): + self.P2PDictionary.update({"persistent_group_object": + self.persistent_group_object}) + + # Run p2p_invite + def run(self): + try: + self.p2p_interface.Invite(self.P2PDictionary) + + except: + print "Error:\n Invalid Arguements" + usage() + os._exit(0) + + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + +if __name__ == "__main__": + # Defaults for optional inputs + addr = None + persistent_group_object = None + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:o:w:a:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + elif (key == "-a"): + addr = value + # Persistent group object path + elif (key == "-o"): + persistent_group_object = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + if (addr == None): + print "Error:\n peer address is required" + usage() + quit() + + try: + p2p_invite_test = \ + P2P_Invite(interface_name,wpas_dbus_interface, + addr,persistent_group_object) + except: + print "Error:\n Invalid Arguements" + usage() + os._exit(1) + + p2p_invite_test.constructArguements() + p2p_invite_test.start() + time.sleep(10) + print "Error:\n p2p_invite timed out" + os._exit(0) diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py new file mode 100644 index 0000000..bb3c1e4 --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_listen.py @@ -0,0 +1,182 @@ +#!/usr/bin/python +# Tests P2P_Find +# Will listen +# Then Program will exit +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> [-t <timeout>] \ " \ + % sys.argv[0] + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -t = timeout = 0s (infinite)" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i wlan0 -t 5" % sys.argv[0] + +# Required Signals +def p2pStateChange(status): + print status + +class P2P_Listen(threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.timeout = int(timeout) + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + self.bus.add_signal_receiver(p2pStateChange, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="P2PStateChanged") + + # Run p2p_find + def run(self): + # Sets up p2p_listen + self.p2p_interface.Listen(int(self.timeout)) + + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + +if __name__ == "__main__": + + # Defaults for optional inputs + timeout = 0 + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:t:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Timeout + elif (key == "-t"): + if ( int(value) >= 0): + timeout = value + else: + print "Error:\n Timeout cannot be negative" + usage() + quit() + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + # Constructor + try: + p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout) + + except: + print "Error:\n Invalid wpas_dbus_interface" + usage() + quit() + + # Start P2P_Find + p2p_listen_test.start() + + try: + # If timeout is 0, then run forever + if (int(p2p_listen_test.timeout) == 0): + while(True): + pass + # Else sleep for (timeout) + else: + time.sleep(int(p2p_listen_test.timeout)) + + except: + pass + + quit() diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py new file mode 100644 index 0000000..f6c03b0 --- /dev/null +++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +# Tests p2p_stop_find +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print "Usage:" + print " %s -i <interface_name> \ " \ + % sys.argv[0] + print " [-w <wpas_dbus_interface>]" + print "Options:" + print " -i = interface name" + print " -w = wpas dbus interface = fi.w1.wpa_supplicant1" + print "Example:" + print " %s -i wlan0" % sys.argv[0] + +# Required Signals +def deviceLost(devicepath): + print "Device lost: %s" % (devicepath) + +def p2pStateChange(status): + print status + os._exit(0) + +class P2P_Stop_Find (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.timeout = timeout + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException, exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print error + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Signals + self.bus.add_signal_receiver(deviceLost, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceLost") + self.bus.add_signal_receiver(p2pStateChange, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="P2PStateChanged") + + # Runs p2p_stop_find + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + self.p2p_interface.StopFind() + gobject.MainLoop().run() + + +if __name__ == "__main__": + # Needed because P2PStateChanged signal is not caught + timeout = 5 + # Defaults for optional inputs + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"ht:i:w:") + + except getopt.GetoptError: + usage() + quit() + + # If theres a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print "Error:\n interface_name is required" + usage() + quit() + + # Constructor + try: + p2p_stop_find_test = P2P_Stop_Find(interface_name, + wpas_dbus_interface,timeout) + + except: + print "Error:\n Invalid wpas_dbus_interface" + usage() + quit() + + # Start P2P_Find + p2p_stop_find_test.start() + + try: + time.sleep(int(p2p_stop_find_test.timeout)) + + except: + pass + + print "p2p find stopped" + quit() diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index 1fd6e00..efa9be8 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -19,7 +19,7 @@ #include "gas_query.h" -#define GAS_QUERY_TIMEOUT 5 +#define GAS_QUERY_TIMEOUT_PERIOD 5 struct gas_query_pending { @@ -457,7 +457,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, return -1; } - eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout, + eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); return dialog_token; diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 515d94b..7b5b20e 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -15,6 +15,7 @@ #include "utils/pcsc_funcs.h" #include "drivers/driver.h" #include "eap_common/eap_defs.h" +#include "eap_peer/eap.h" #include "eap_peer/eap_methods.h" #include "wpa_supplicant_i.h" #include "config.h" @@ -329,7 +330,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, wpa_printf(MSG_DEBUG, "No room for EAP Methods"); return NULL; } - r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap)); + r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap)); if (r->eap == NULL) return NULL; @@ -365,7 +366,7 @@ static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count) return NULL; } - realm = os_zalloc(num * sizeof(struct nai_realm)); + realm = os_calloc(num, sizeof(struct nai_realm)); if (realm == NULL) return NULL; @@ -550,6 +551,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) break; if (os_memcmp(pos, plmn, 3) == 0) return 1; /* Found matching PLMN */ + pos += 3; } } @@ -561,7 +563,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) static int build_root_nai(char *nai, size_t nai_len, const char *imsi, - char prefix) + size_t mnc_len, char prefix) { const char *sep, *msin; char *end, *pos; @@ -579,12 +581,16 @@ static int build_root_nai(char *nai, size_t nai_len, const char *imsi, return -1; } sep = os_strchr(imsi, '-'); - if (sep == NULL) + if (sep) { + plmn_len = sep - imsi; + msin = sep + 1; + } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) { + plmn_len = 3 + mnc_len; + msin = imsi + plmn_len; + } else return -1; - plmn_len = sep - imsi; if (plmn_len != 5 && plmn_len != 6) return -1; - msin = sep + 1; msin_len = os_strlen(msin); pos = nai; @@ -615,7 +621,7 @@ static int build_root_nai(char *nai, size_t nai_len, const char *imsi, static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix) { char nai[100]; - if (build_root_nai(nai, sizeof(nai), imsi, prefix) < 0) + if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0) return -1; return wpa_config_set_quoted(ssid, "identity", nai); } @@ -623,6 +629,18 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix) #endif /* INTERWORKING_3GPP */ +static int interworking_set_hs20_params(struct wpa_ssid *ssid) +{ + if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0) + return -1; + if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) + return -1; + if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) + return -1; + return 0; +} + + static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { @@ -688,6 +706,9 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, os_memcpy(ssid->ssid, ie + 2, ie[1]); ssid->ssid_len = ie[1]; + if (interworking_set_hs20_params(ssid) < 0) + goto fail; + /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */ if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) { wpa_printf(MSG_DEBUG, "EAP-SIM not supported"); @@ -730,6 +751,255 @@ fail: } +static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, + size_t rc_len) +{ + const u8 *pos, *end; + u8 lens; + + if (ie == NULL) + return 0; + + pos = ie + 2; + end = ie + 2 + ie[1]; + + /* Roaming Consortium element: + * Number of ANQP OIs + * OI #1 and #2 lengths + * OI #1, [OI #2], [OI #3] + */ + + if (pos + 2 > end) + return 0; + + pos++; /* skip Number of ANQP OIs */ + lens = *pos++; + if (pos + (lens & 0x0f) + (lens >> 4) > end) + return 0; + + if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + pos += lens & 0x0f; + + if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + pos += lens >> 4; + + if (pos < end && (size_t) (end - pos) == rc_len && + os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + + return 0; +} + + +static int roaming_consortium_anqp_match(const struct wpabuf *anqp, + const u8 *rc_id, size_t rc_len) +{ + const u8 *pos, *end; + u8 len; + + if (anqp == NULL) + return 0; + + pos = wpabuf_head(anqp); + end = pos + wpabuf_len(anqp); + + /* Set of <OI Length, OI> duples */ + while (pos < end) { + len = *pos++; + if (pos + len > end) + break; + if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + return 1; + pos += len; + } + + return 0; +} + + +static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, + const u8 *rc_id, size_t rc_len) +{ + return roaming_consortium_element_match(ie, rc_id, rc_len) || + roaming_consortium_anqp_match(anqp, rc_id, rc_len); +} + + +static struct wpa_cred * interworking_credentials_available_roaming_consortium( + struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + struct wpa_cred *cred, *selected = NULL; + const u8 *ie; + + ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); + + if (ie == NULL && bss->anqp_roaming_consortium == NULL) + return NULL; + + if (wpa_s->conf->cred == NULL) + return NULL; + + for (cred = wpa_s->conf->cred; cred; cred = cred->next) { + if (cred->roaming_consortium_len == 0) + continue; + + if (!roaming_consortium_match(ie, bss->anqp_roaming_consortium, + cred->roaming_consortium, + cred->roaming_consortium_len)) + continue; + + if (selected == NULL || + selected->priority < cred->priority) + selected = cred; + } + + return selected; +} + + +static int interworking_set_eap_params(struct wpa_ssid *ssid, + struct wpa_cred *cred, int ttls) +{ + if (cred->eap_method) { + ttls = cred->eap_method->vendor == EAP_VENDOR_IETF && + cred->eap_method->method == EAP_TYPE_TTLS; + + os_free(ssid->eap.eap_methods); + ssid->eap.eap_methods = + os_malloc(sizeof(struct eap_method_type) * 2); + if (ssid->eap.eap_methods == NULL) + return -1; + os_memcpy(ssid->eap.eap_methods, cred->eap_method, + sizeof(*cred->eap_method)); + ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF; + ssid->eap.eap_methods[1].method = EAP_TYPE_NONE; + } + + if (ttls && cred->username && cred->username[0]) { + const char *pos; + char *anon; + /* Use anonymous NAI in Phase 1 */ + pos = os_strchr(cred->username, '@'); + if (pos) { + size_t buflen = 9 + os_strlen(pos) + 1; + anon = os_malloc(buflen); + if (anon == NULL) + return -1; + os_snprintf(anon, buflen, "anonymous%s", pos); + } else if (cred->realm) { + size_t buflen = 10 + os_strlen(cred->realm) + 1; + anon = os_malloc(buflen); + if (anon == NULL) + return -1; + os_snprintf(anon, buflen, "anonymous@%s", cred->realm); + } else { + anon = os_strdup("anonymous"); + if (anon == NULL) + return -1; + } + if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) < + 0) { + os_free(anon); + return -1; + } + os_free(anon); + } + + if (cred->username && cred->username[0] && + wpa_config_set_quoted(ssid, "identity", cred->username) < 0) + return -1; + + if (cred->password && cred->password[0]) { + if (cred->ext_password && + wpa_config_set(ssid, "password", cred->password, 0) < 0) + return -1; + if (!cred->ext_password && + wpa_config_set_quoted(ssid, "password", cred->password) < + 0) + return -1; + } + + if (cred->client_cert && cred->client_cert[0] && + wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0) + return -1; + + if (cred->private_key && cred->private_key[0] && + wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0) + return -1; + + if (cred->private_key_passwd && cred->private_key_passwd[0] && + wpa_config_set_quoted(ssid, "private_key_passwd", + cred->private_key_passwd) < 0) + return -1; + + if (cred->phase1) { + os_free(ssid->eap.phase1); + ssid->eap.phase1 = os_strdup(cred->phase1); + } + if (cred->phase2) { + os_free(ssid->eap.phase2); + ssid->eap.phase2 = os_strdup(cred->phase2); + } + + if (cred->ca_cert && cred->ca_cert[0] && + wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0) + return -1; + + return 0; +} + + +static int interworking_connect_roaming_consortium( + struct wpa_supplicant *wpa_s, struct wpa_cred *cred, + struct wpa_bss *bss, const u8 *ssid_ie) +{ + struct wpa_ssid *ssid; + + wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on " + "roaming consortium match", MAC2STR(bss->bssid)); + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) + return -1; + wpas_notify_network_added(wpa_s, ssid); + wpa_config_set_network_defaults(ssid); + ssid->priority = cred->priority; + ssid->temporary = 1; + ssid->ssid = os_zalloc(ssid_ie[1] + 1); + if (ssid->ssid == NULL) + goto fail; + os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]); + ssid->ssid_len = ssid_ie[1]; + + if (interworking_set_hs20_params(ssid) < 0) + goto fail; + + if (cred->eap_method == NULL) { + wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for " + "credential using roaming consortium"); + goto fail; + } + + if (interworking_set_eap_params( + ssid, cred, + cred->eap_method->vendor == EAP_VENDOR_IETF && + cred->eap_method->method == EAP_TYPE_TTLS) < 0) + goto fail; + + wpa_config_update_prio_list(wpa_s->conf); + interworking_reconnect(wpa_s); + + return 0; + +fail: + wpas_notify_network_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + return -1; +} + + int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_cred *cred; @@ -749,6 +1019,22 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) return -1; } + if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { + /* + * We currently support only HS 2.0 networks and those are + * required to use WPA2-Enterprise. + */ + wpa_printf(MSG_DEBUG, "Interworking: Network does not use " + "RSN"); + return -1; + } + + cred = interworking_credentials_available_roaming_consortium(wpa_s, + bss); + if (cred) + return interworking_connect_roaming_consortium(wpa_s, cred, + bss, ie); + realm = nai_realm_parse(bss->anqp_nai_realm, &count); if (realm == NULL) { wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " @@ -800,60 +1086,11 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) os_memcpy(ssid->ssid, ie + 2, ie[1]); ssid->ssid_len = ie[1]; - if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF, - eap->method), 0) < 0) - goto fail; - - if (eap->method == EAP_TYPE_TTLS && - cred->username && cred->username[0]) { - const char *pos; - char *anon; - /* Use anonymous NAI in Phase 1 */ - pos = os_strchr(cred->username, '@'); - if (pos) { - size_t buflen = 9 + os_strlen(pos) + 1; - anon = os_malloc(buflen); - if (anon == NULL) - goto fail; - os_snprintf(anon, buflen, "anonymous%s", pos); - } else if (cred->realm) { - size_t buflen = 10 + os_strlen(cred->realm) + 1; - anon = os_malloc(buflen); - if (anon == NULL) - goto fail; - os_snprintf(anon, buflen, "anonymous@%s", cred->realm); - } else { - anon = os_strdup("anonymous"); - if (anon == NULL) - goto fail; - } - if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) < - 0) { - os_free(anon); - goto fail; - } - os_free(anon); - } - - if (cred->username && cred->username[0] && - wpa_config_set_quoted(ssid, "identity", cred->username) < 0) - goto fail; - - if (cred->password && cred->password[0] && - wpa_config_set_quoted(ssid, "password", cred->password) < 0) - goto fail; - - if (cred->client_cert && cred->client_cert[0] && - wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0) - goto fail; - - if (cred->private_key && cred->private_key[0] && - wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0) + if (interworking_set_hs20_params(ssid) < 0) goto fail; - if (cred->private_key_passwd && cred->private_key_passwd[0] && - wpa_config_set_quoted(ssid, "private_key_passwd", - cred->private_key_passwd) < 0) + if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF, + eap->method), 0) < 0) goto fail; switch (eap->method) { @@ -899,8 +1136,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) break; } - if (cred->ca_cert && cred->ca_cert[0] && - wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0) + if (interworking_set_eap_params(ssid, cred, + eap->method == EAP_TYPE_TTLS) < 0) goto fail; nai_realm_free(realm, count); @@ -1027,6 +1264,13 @@ static struct wpa_cred * interworking_credentials_available( if (!cred) cred = cred2; + cred2 = interworking_credentials_available_roaming_consortium(wpa_s, + bss); + if (cred && cred2 && cred2->priority >= cred->priority) + cred = cred2; + if (!cred) + cred = cred2; + return cred; } @@ -1071,8 +1315,17 @@ static int interworking_home_sp(struct wpa_supplicant *wpa_s, for (cred = wpa_s->conf->cred; cred; cred = cred->next) { #ifdef INTERWORKING_3GPP - if (cred->imsi && - build_root_nai(nai, sizeof(nai), cred->imsi, 0) == 0) { + char *imsi = NULL; + int mnc_len = 0; + if (cred->imsi) + imsi = cred->imsi; + else if (cred->pcsc && wpa_s->conf->pcsc_reader && + wpa_s->scard && wpa_s->imsi[0]) { + imsi = wpa_s->imsi; + mnc_len = wpa_s->mnc_len; + } + if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) + == 0) { realm = os_strchr(nai, '@'); if (realm) realm++; @@ -1138,6 +1391,16 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) cred = interworking_credentials_available(wpa_s, bss); if (!cred) continue; + if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { + /* + * We currently support only HS 2.0 networks and those + * are required to use WPA2-Enterprise. + */ + wpa_printf(MSG_DEBUG, "Interworking: Credential match " + "with " MACSTR " but network does not use " + "RSN", MAC2STR(bss->bssid)); + continue; + } count++; res = interworking_home_sp(wpa_s, bss->anqp_domain_name); if (res > 0) @@ -1148,7 +1411,9 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) type = "unknown"; wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s", MAC2STR(bss->bssid), type); - if (wpa_s->auto_select) { + if (wpa_s->auto_select || + (wpa_s->conf->auto_interworking && + wpa_s->auto_network_select)) { if (selected == NULL || cred->priority > selected_prio) { selected = bss; @@ -1178,7 +1443,16 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) if (interworking_find_network_match(wpa_s)) { wpa_printf(MSG_DEBUG, "Interworking: Possible BSS " "match for enabled network configurations"); - interworking_reconnect(wpa_s); + if (wpa_s->auto_select) + interworking_reconnect(wpa_s); + return; + } + + if (wpa_s->auto_network_select) { + wpa_printf(MSG_DEBUG, "Interworking: Continue " + "scanning after ANQP fetch"); + wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, + 0); return; } @@ -1226,7 +1500,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) } -static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) +void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; @@ -1484,6 +1758,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) { interworking_stop_fetch_anqp(wpa_s); wpa_s->network_select = 1; + wpa_s->auto_network_select = 0; wpa_s->auto_select = !!auto_select; wpa_printf(MSG_DEBUG, "Interworking: Start scan for network " "selection"); @@ -1493,3 +1768,84 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) return 0; } + + +static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, + enum gas_query_result result, + const struct wpabuf *adv_proto, + const struct wpabuf *resp, u16 status_code) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR + " dialog_token=%d status_code=%d resp_len=%d", + MAC2STR(addr), dialog_token, status_code, + resp ? (int) wpabuf_len(resp) : -1); + if (!resp) + return; + + wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = wpabuf_dup(resp); + if (wpa_s->last_gas_resp == NULL) + return; + os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); + wpa_s->last_gas_dialog_token = dialog_token; +} + + +int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, + const struct wpabuf *adv_proto, + const struct wpabuf *query) +{ + struct wpabuf *buf; + int ret = 0; + int freq; + struct wpa_bss *bss; + int res; + size_t len; + u8 query_resp_len_limit = 0, pame_bi = 0; + + freq = wpa_s->assoc_freq; + bss = wpa_bss_get_bssid(wpa_s, dst); + if (bss) + freq = bss->freq; + if (freq <= 0) + return -1; + + wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)", + MAC2STR(dst), freq); + wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto); + wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query); + + len = 3 + wpabuf_len(adv_proto) + 2; + if (query) + len += wpabuf_len(query); + buf = gas_build_initial_req(0, len); + if (buf == NULL) + return -1; + + /* Advertisement Protocol IE */ + wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); + wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */ + wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) | + (pame_bi ? 0x80 : 0)); + wpabuf_put_buf(buf, adv_proto); + + /* GAS Query */ + if (query) { + wpabuf_put_le16(buf, wpabuf_len(query)); + wpabuf_put_buf(buf, query); + } else + wpabuf_put_le16(buf, 0); + + res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s); + if (res < 0) { + wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request"); + ret = -1; + } else + wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token " + "%u", res); + + wpabuf_free(buf); + return ret; +} diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 7dda8d8..cb8438e 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -1,6 +1,6 @@ /* * Interworking (IEEE 802.11u) - * Copyright (c) 2011, Qualcomm Atheros + * Copyright (c) 2011-2012, Qualcomm Atheros * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -17,9 +17,13 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code); +int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, + const struct wpabuf *adv_proto, + const struct wpabuf *query); int interworking_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_select(struct wpa_supplicant *wpa_s, int auto_select); int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); +void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); #endif /* INTERWORKING_H */ diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c index 80aac77..19f7ce6 100644 --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -101,20 +101,31 @@ static void license(void) } -static void wpa_supplicant_fd_workaround(void) +static void wpa_supplicant_fd_workaround(int start) { #ifdef __linux__ - int s, i; + static int fd[3] = { -1, -1, -1 }; + int i; /* When started from pcmcia-cs scripts, wpa_supplicant might start with * fd 0, 1, and 2 closed. This will cause some issues because many * places in wpa_supplicant are still printing out to stdout. As a * workaround, make sure that fd's 0, 1, and 2 are not used for other * sockets. */ - for (i = 0; i < 3; i++) { - s = open("/dev/null", O_RDWR); - if (s > 2) { - close(s); - break; + if (start) { + for (i = 0; i < 3; i++) { + fd[i] = open("/dev/null", O_RDWR); + if (fd[i] > 2) { + close(fd[i]); + fd[i] = -1; + break; + } + } + } else { + for (i = 0; i < 3; i++) { + if (fd[i] >= 0) { + close(fd[i]); + fd[i] = -1; + } } } #endif /* __linux__ */ @@ -140,7 +151,7 @@ int main(int argc, char *argv[]) return -1; iface_count = 1; - wpa_supplicant_fd_workaround(); + wpa_supplicant_fd_workaround(1); for (;;) { c = getopt(argc, argv, @@ -241,8 +252,8 @@ int main(int argc, char *argv[]) break; case 'N': iface_count++; - iface = os_realloc(ifaces, iface_count * - sizeof(struct wpa_interface)); + iface = os_realloc_array(ifaces, iface_count, + sizeof(struct wpa_interface)); if (iface == NULL) goto out; ifaces = iface; @@ -288,6 +299,7 @@ int main(int argc, char *argv[]) wpa_supplicant_deinit(global); out: + wpa_supplicant_fd_workaround(0); os_free(ifaces); os_free(params.pid_file); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 55cb243..cfe0433 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -61,6 +61,27 @@ #define P2P_MAX_INITIAL_CONN_WAIT 10 #endif /* P2P_MAX_INITIAL_CONN_WAIT */ +#ifndef P2P_CONCURRENT_SEARCH_DELAY +#ifdef ANDROID_P2P +#define P2P_CONCURRENT_SEARCH_DELAY 0 +#else +#define P2P_CONCURRENT_SEARCH_DELAY 500 +#endif +#endif /* P2P_CONCURRENT_SEARCH_DELAY */ + +enum p2p_group_removal_reason { + P2P_GROUP_REMOVAL_UNKNOWN, + P2P_GROUP_REMOVAL_SILENT, + P2P_GROUP_REMOVAL_FORMATION_FAILED, + P2P_GROUP_REMOVAL_REQUESTED, + P2P_GROUP_REMOVAL_IDLE_TIMEOUT, + P2P_GROUP_REMOVAL_UNAVAILABLE, + P2P_GROUP_REMOVAL_GO_ENDING_SESSION, +#ifdef ANDROID_P2P + P2P_GROUP_REMOVAL_FREQ_CONFLICT +#endif +}; + #ifdef ANDROID_P2P static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s); #endif @@ -129,6 +150,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) { struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *ifs; struct wpa_driver_scan_params params; int ret; struct wpabuf *wps_ie, *ies; @@ -138,6 +160,18 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { + if (ifs->sta_scan_pending && + wpas_p2p_in_progress(wpa_s) == 2) { + wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow " + "pending station mode scan to be " + "completed on interface %s", ifs->ifname); + wpa_s->p2p_cb_on_scan_complete = 1; + wpa_supplicant_req_scan(ifs, 0, 0); + return 1; + } + } + os_memset(¶ms, 0, sizeof(params)); /* P2P Wildcard SSID */ @@ -241,14 +275,19 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s, } -static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) +static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, + enum p2p_group_removal_reason removal_reason) { struct wpa_ssid *ssid; char *gtype; const char *reason; ssid = wpa_s->current_ssid; +#ifdef ANDROID_P2P + if ((ssid == NULL) && (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) { +#else if (ssid == NULL) { +#endif /* * The current SSID was not known, but there may still be a * pending P2P group interface waiting for provisioning. @@ -261,6 +300,11 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) break; ssid = ssid->next; } + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "P2P: P2P group interface " + "not found"); + return -1; + } } if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO) gtype = "GO"; @@ -279,10 +323,13 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", wpa_s->ifname, wpa_s->cross_connect_uplink); } - switch (wpa_s->removal_reason) { + switch (removal_reason) { case P2P_GROUP_REMOVAL_REQUESTED: reason = " reason=REQUESTED"; break; + case P2P_GROUP_REMOVAL_FORMATION_FAILED: + reason = " reason=FORMATION_FAILED"; + break; case P2P_GROUP_REMOVAL_IDLE_TIMEOUT: reason = " reason=IDLE"; break; @@ -301,7 +348,7 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) reason = ""; break; } - if (!silent) { + if (removal_reason != P2P_GROUP_REMOVAL_SILENT) { wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s", wpa_s->ifname, gtype, reason); @@ -310,7 +357,7 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); - if (!silent && ssid) + if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid) wpas_notify_p2p_group_removed(wpa_s, ssid, gtype); if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { @@ -327,7 +374,7 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) if (wpa_s && ifname) wpa_drv_if_remove(wpa_s, type, ifname); os_free(ifname); - return; + return 0; } wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network"); @@ -360,6 +407,8 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) wpa_supplicant_ap_deinit(wpa_s); else wpa_drv_deinit_p2p_cli(wpa_s); + + return 0; } @@ -517,6 +566,7 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, *s; u8 *n; size_t i; + int found = 0; ssid = wpa_s->current_ssid; if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || @@ -537,17 +587,40 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s, for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) { if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr, - ETH_ALEN) == 0) - return; /* already in list */ + ETH_ALEN) != 0) + continue; + + if (i == s->num_p2p_clients - 1) + return; /* already the most recent entry */ + + /* move the entry to mark it most recent */ + os_memmove(s->p2p_client_list + i * ETH_ALEN, + s->p2p_client_list + (i + 1) * ETH_ALEN, + (s->num_p2p_clients - i - 1) * ETH_ALEN); + os_memcpy(s->p2p_client_list + + (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN); + found = 1; + break; } - n = os_realloc(s->p2p_client_list, - (s->num_p2p_clients + 1) * ETH_ALEN); - if (n == NULL) - return; - os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN); - s->p2p_client_list = n; - s->num_p2p_clients++; + if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) { + n = os_realloc_array(s->p2p_client_list, + s->num_p2p_clients + 1, ETH_ALEN); + if (n == NULL) + return; + os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN); + s->p2p_client_list = n; + s->num_p2p_clients++; + } else if (!found) { + /* Not enough room for an additional entry - drop the oldest + * entry */ + os_memmove(s->p2p_client_list, + s->p2p_client_list + ETH_ALEN, + (s->num_p2p_clients - 1) * ETH_ALEN); + os_memcpy(s->p2p_client_list + + (s->num_p2p_clients - 1) * ETH_ALEN, + addr, ETH_ALEN); + } #ifndef CONFIG_NO_CONFIG_WRITE if (wpa_s->parent->conf->update_config && @@ -580,7 +653,8 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, if (!success) { wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); - wpas_p2p_group_delete(wpa_s, 0); + wpas_p2p_group_delete(wpa_s, + P2P_GROUP_REMOVAL_FORMATION_FAILED); return; } @@ -835,6 +909,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION : WPAS_MODE_P2P_GO; ssid->frequency = params->freq; + ssid->ht40 = params->ht40; ssid->ssid = os_zalloc(params->ssid_len + 1); if (ssid->ssid) { os_memcpy(ssid->ssid, params->ssid, params->ssid_len); @@ -845,6 +920,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, ssid->proto = WPA_PROTO_RSN; ssid->pairwise_cipher = WPA_CIPHER_CCMP; ssid->passphrase = os_strdup(params->passphrase); + ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity; wpa_s->ap_configured_cb = p2p_go_configured; wpa_s->ap_configured_cb_ctx = wpa_s; @@ -1032,6 +1108,9 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) return; } + if (wpa_s->p2p_go_ht40) + res->ht40 = 1; + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS); wpas_notify_p2p_go_neg_completed(wpa_s, res); @@ -1449,6 +1528,62 @@ static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_WIFI_DISPLAY +static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s, + struct wpabuf *resp, u8 srv_trans_id, + const u8 *query, size_t query_len) +{ + const u8 *pos; + u8 role; + u8 *len_pos; + + wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len); + + if (!wpa_s->global->wifi_display) { + wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available"); + wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY, + srv_trans_id); + return; + } + + if (query_len < 1) { + wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device " + "Role"); + return; + } + + if (wpabuf_tailroom(resp) < 5) + return; + + pos = query; + role = *pos++; + wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role); + + /* TODO: role specific handling */ + + /* Length (to be filled) */ + len_pos = wpabuf_put(resp, 2); + wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY); + wpabuf_put_u8(resp, srv_trans_id); + wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */ + + while (pos < query + query_len) { + if (*pos < MAX_WFD_SUBELEMS && + wpa_s->global->wfd_subelem[*pos] && + wpabuf_tailroom(resp) >= + wpabuf_len(wpa_s->global->wfd_subelem[*pos])) { + wpa_printf(MSG_DEBUG, "P2P: Add WSD response " + "subelement %u", *pos); + wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]); + } + pos++; + } + + WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); +} +#endif /* CONFIG_WIFI_DISPLAY */ + + void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { @@ -1540,6 +1675,12 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, wpas_sd_req_upnp(wpa_s, resp, srv_trans_id, pos, tlv_end - pos); break; +#ifdef CONFIG_WIFI_DISPLAY + case P2P_SERV_WIFI_DISPLAY: + wpas_sd_req_wfd(wpa_s, resp, srv_trans_id, + pos, tlv_end - pos); + break; +#endif /* CONFIG_WIFI_DISPLAY */ default: wpa_printf(MSG_DEBUG, "P2P: Unavailable service " "protocol %u", srv_proto); @@ -1657,6 +1798,88 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, } +#ifdef CONFIG_WIFI_DISPLAY + +static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst, + const struct wpabuf *tlvs) +{ + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return 0; + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) + return 0; + return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs); +} + + +#define MAX_WFD_SD_SUBELEMS 20 + +static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role, + const char *subelems) +{ + u8 *len; + const char *pos; + int val; + int count = 0; + + len = wpabuf_put(tlvs, 2); + wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */ + wpabuf_put_u8(tlvs, id); /* Service Transaction ID */ + + wpabuf_put_u8(tlvs, role); + + pos = subelems; + while (*pos) { + val = atoi(pos); + if (val >= 0 && val < 256) { + wpabuf_put_u8(tlvs, val); + count++; + if (count == MAX_WFD_SD_SUBELEMS) + break; + } + pos = os_strchr(pos + 1, ','); + if (pos == NULL) + break; + pos++; + } + + WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2); +} + + +u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *role) +{ + struct wpabuf *tlvs; + u64 ret; + const char *subelems; + u8 id = 1; + + subelems = os_strchr(role, ' '); + if (subelems == NULL) + return 0; + subelems++; + + tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS)); + if (tlvs == NULL) + return 0; + + if (os_strstr(role, "[source]")) + wfd_add_sd_req_role(tlvs, id++, 0x00, subelems); + if (os_strstr(role, "[pri-sink]")) + wfd_add_sd_req_role(tlvs, id++, 0x01, subelems); + if (os_strstr(role, "[sec-sink]")) + wfd_add_sd_req_role(tlvs, id++, 0x02, subelems); + if (os_strstr(role, "[source+sink]")) + wfd_add_sd_req_role(tlvs, id++, 0x03, subelems); + + ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs); + wpabuf_free(tlvs); + return ret; +} + +#endif /* CONFIG_WIFI_DISPLAY */ + + int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req) { if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) @@ -2084,7 +2307,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, MAC2STR(sa), op_freq); if (s) { wpas_p2p_group_add_persistent( - wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0); + wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0); } else if (bssid) { wpas_p2p_join(wpa_s, bssid, go_dev_addr, wpa_s->p2p_wps_method, 0); @@ -2151,7 +2374,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid) } wpas_p2p_group_add_persistent(wpa_s, ssid, - ssid->mode == WPAS_MODE_P2P_GO, 0); + ssid->mode == WPAS_MODE_P2P_GO, 0, 0); } @@ -2288,26 +2511,48 @@ struct p2p_oper_class_map { enum { BW20, BW40PLUS, BW40MINUS } bw; }; +static struct p2p_oper_class_map op_class[] = { + { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 }, + { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 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, 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 }, + { -1, 0, 0, 0, 0, BW20 } +}; + + +static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + u8 channel, u8 bw) +{ + int flag; + + if (!has_channel(wpa_s->global, mode, channel, &flag)) + return -1; + if (bw == BW40MINUS && + (!(flag & HOSTAPD_CHAN_HT40MINUS) || + !has_channel(wpa_s->global, mode, channel - 4, NULL))) + return 0; + if (bw == BW40PLUS && + (!(flag & HOSTAPD_CHAN_HT40PLUS) || + !has_channel(wpa_s->global, mode, channel + 4, NULL))) + return 0; + return 1; +} + + static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, struct p2p_channels *chan) { struct hostapd_hw_modes *mode; int cla, op; - struct p2p_oper_class_map op_class[] = { - { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 }, - { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 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, 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 }, - { -1, 0, 0, 0, 0, BW20 } - }; if (wpa_s->hw.modes == NULL) { wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching " @@ -2327,16 +2572,7 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, if (mode == NULL) continue; for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { - int flag; - if (!has_channel(wpa_s->global, mode, ch, &flag)) - continue; - if (o->bw == BW40MINUS && - (!(flag & HOSTAPD_CHAN_HT40MINUS) || - !has_channel(wpa_s->global, mode, ch - 4, NULL))) - continue; - if (o->bw == BW40PLUS && - (!(flag & HOSTAPD_CHAN_HT40PLUS) || - !has_channel(wpa_s->global, mode, ch + 4, NULL))) + if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1) continue; if (reg == NULL) { wpa_printf(MSG_DEBUG, "P2P: Add operating " @@ -2360,6 +2596,32 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, } +int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel) +{ + int op, ret; + + for (op = 0; op_class[op].op_class; op++) { + struct p2p_oper_class_map *o = &op_class[op]; + u8 ch; + + for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { + if (o->mode != HOSTAPD_MODE_IEEE80211A || + o->bw == BW20 || ch != channel) + continue; + ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw); + if (ret < 0) + continue; + else if (ret > 0) + return (o->bw == BW40MINUS) ? -1 : 1; + else + return 0; + } + } + return 0; +} + + static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf, size_t buf_len) { @@ -2540,7 +2802,6 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss; - #ifdef ANDROID_P2P if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT; @@ -2607,13 +2868,14 @@ void wpas_p2p_deinit_global(struct wpa_global *global) { struct wpa_supplicant *wpa_s, *tmp; + wpa_s = global->ifaces; + if (wpa_s) + wpas_p2p_service_flush(wpa_s); + if (global->p2p == NULL) return; /* Remove remaining P2P group interfaces */ - wpa_s = global->ifaces; - if (wpa_s) - wpas_p2p_service_flush(wpa_s); while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) wpa_s = wpa_s->next; while (wpa_s) { @@ -2677,6 +2939,13 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, force_freq, persistent_group); } + /* + * Increase GO config timeout if HT40 is used since it takes some time + * to scan channels for coex purposes before the BSS can be started. + */ + p2p_set_config_timeout(wpa_s->global->p2p, + wpa_s->p2p_go_ht40 ? 255 : 100, 20); + return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group, ssid ? ssid->ssid : NULL, @@ -2881,7 +3150,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, wpa_s->p2p_persistent_id, - wpa_s->p2p_pd_before_go_neg); + wpa_s->p2p_pd_before_go_neg, + wpa_s->p2p_go_ht40); return; } @@ -3177,6 +3447,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) * 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 * 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 @@ -3184,7 +3455,8 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) 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 go_intent, int freq, int persistent_id, int pd, + int ht40) { int force_freq = 0, oper_freq = 0; u8 bssid[ETH_ALEN]; @@ -3216,6 +3488,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_connect_freq = freq; wpa_s->p2p_fallback_to_go_neg = 0; wpa_s->p2p_pd_before_go_neg = !!pd; + wpa_s->p2p_go_ht40 = !!ht40; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); @@ -3447,13 +3720,14 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname) static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params, - int freq) + int freq, int ht40) { u8 bssid[ETH_ALEN]; int res; os_memset(params, 0, sizeof(*params)); params->role_go = 1; + params->ht40 = ht40; if (freq) { wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced " "frequency %d MHz", freq); @@ -3565,7 +3839,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, * i.e., without using Group Owner Negotiation. */ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, - int freq) + int freq, int ht40) { struct p2p_go_neg_results params; unsigned int r; @@ -3623,7 +3897,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, return -1; } - if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40)) return -1; if (params.freq && !p2p_supported_freq(wpa_s->global->p2p, params.freq)) { @@ -3690,7 +3964,7 @@ 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 freq) + int freq, int ht40) { struct p2p_go_neg_results params; int go = 0; @@ -3716,7 +3990,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, if (ssid->mode != WPAS_MODE_P2P_GO) return -1; - if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40)) return -1; params.role_go = 1; @@ -3955,7 +4229,7 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s) int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, - const u8 *dev_id) + const u8 *dev_id, unsigned int search_delay) { wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; @@ -3970,7 +4244,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, wpa_supplicant_cancel_sched_scan(wpa_s); return p2p_find(wpa_s->global->p2p, timeout, type, - num_req_dev_types, req_dev_types, dev_id); + num_req_dev_types, req_dev_types, dev_id, + search_delay); } @@ -4263,7 +4538,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) } if (!wpa_s->show_group_started || !ssid) - return; + goto done; wpa_s->show_group_started = 0; @@ -4305,6 +4580,19 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) if (network_id < 0) network_id = ssid->id; wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1); + +done: + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after successful connection"); + p2p_increase_search_delay( + wpa_s->global->p2p, + wpas_p2p_search_delay(wpa_s)); + } + } } @@ -4360,8 +4648,7 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx) wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate " "group"); - wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT; - wpas_p2p_group_delete(wpa_s, 0); + wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT); } @@ -4441,8 +4728,8 @@ void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, wpa_s->current_ssid->mode == WPAS_MODE_INFRA) { wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group " "session is ending"); - wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION; - wpas_p2p_group_delete(wpa_s, 0); + wpas_p2p_group_delete(wpa_s, + P2P_GROUP_REMOVAL_GO_ENDING_SESSION); } } @@ -4810,7 +5097,8 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) found = 1; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); - wpas_p2p_group_delete(wpa_s, 0); + wpas_p2p_group_delete(wpa_s, + P2P_GROUP_REMOVAL_REQUESTED); break; } } @@ -4831,8 +5119,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not " "being available anymore"); - wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE; - wpas_p2p_group_delete(wpa_s, 0); + wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE); } @@ -4878,10 +5165,7 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s) if (wpa_s == NULL) return -1; - wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED; - wpas_p2p_group_delete(wpa_s, 0); - - return 0; + return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED); } @@ -4984,13 +5268,14 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpa_s = wpa_s->parent; offchannel_send_action_done(wpa_s); if (group_added) - wpas_p2p_group_delete(group, 1); + wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT); wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation"); 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_persistent_id, - wpa_s->p2p_pd_before_go_neg); + wpa_s->p2p_pd_before_go_neg, + wpa_s->p2p_go_ht40); } @@ -5010,6 +5295,44 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s) return 1; } + +unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s) +{ + const char *rn, *rn2; + struct wpa_supplicant *ifs; + + if (wpa_s->wpa_state > WPA_SCANNING) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to " + "concurrent operation", + P2P_CONCURRENT_SEARCH_DELAY); + return P2P_CONCURRENT_SEARCH_DELAY; + } + + if (!wpa_s->driver->get_radio_name) + return 0; + rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv); + if (rn == NULL || rn[0] == '\0') + return 0; + + for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { + if (ifs == wpa_s || !ifs->driver->get_radio_name) + continue; + + rn2 = ifs->driver->get_radio_name(ifs->drv_priv); + if (!rn2 || os_strcmp(rn, rn2) != 0) + continue; + if (ifs->wpa_state > WPA_SCANNING) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search " + "delay due to concurrent operation on " + "interface %s", + P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname); + return P2P_CONCURRENT_SEARCH_DELAY; + } + } + + return 0; +} + #ifdef ANDROID_P2P int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq) { @@ -5039,8 +5362,7 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq) * P2P connection. So remove the interface */ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel" "concurrent mode frequency conflict"); - iface->removal_reason = P2P_GROUP_REMOVAL_FREQ_CONFLICT; - wpas_p2p_group_delete(iface, 0); + wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT); } else { /* Existing connection has the priority. Disable the newly * selected network and let the application know about it. diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 5af323f..bbdd83e 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -21,7 +21,7 @@ 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 pd, int ht40); void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration); void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, @@ -32,10 +32,10 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, #endif int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, - int freq); + int freq, int ht40); int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, - int freq); + int freq, int ht40); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, @@ -57,7 +57,7 @@ enum p2p_discovery_type; int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, - const u8 *dev_id); + const u8 *dev_id, unsigned int search_delay); void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s); int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout); int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, @@ -90,6 +90,8 @@ u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs); u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 version, const char *query); +u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *role); int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req); void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, const u8 *dst, u8 dialog_token, @@ -149,5 +151,8 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s); +int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel); +unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); #endif /* P2P_SUPPLICANT_H */ diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 8df21d9..d8db81f 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -89,6 +89,9 @@ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s) count++; ssid = ssid->next; } + if (wpa_s->conf->cred && wpa_s->conf->interworking && + wpa_s->conf->auto_interworking) + count++; return count; } @@ -138,7 +141,7 @@ static void int_array_concat(int **res, const int *a) reslen = int_array_len(*res); alen = int_array_len(a); - n = os_realloc(*res, (reslen + alen + 1) * sizeof(int)); + n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); if (n == NULL) { os_free(*res); *res = NULL; @@ -385,9 +388,7 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ -static struct wpabuf * -wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params) +static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; #ifdef CONFIG_WPS @@ -475,15 +476,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s)) { - if (wpa_s->wpa_state == WPA_SCANNING) { + if (wpa_s->sta_scan_pending && + wpas_p2p_in_progress(wpa_s) == 2 && + wpa_s->p2p_cb_on_scan_complete) { + wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " + "mode scan during P2P search"); + } else { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " "while P2P operation is in progress"); + wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); - } else { - wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while " - "P2P operation is in progress"); + return; } - return; } #endif /* CONFIG_P2P */ @@ -642,7 +646,7 @@ ssid_list_set: #endif /* CONFIG_P2P */ wpa_supplicant_optimize_freqs(wpa_s, ¶ms); - extra_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); + extra_ie = wpa_supplicant_extra_ies(wpa_s); #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0) @@ -771,7 +775,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) struct wpa_driver_scan_params *scan_params; enum wpa_states prev_state; struct wpa_ssid *ssid = NULL; - struct wpabuf *wps_ie = NULL; + struct wpabuf *extra_ie = NULL; int ret; unsigned int max_sched_scan_ssids; int wildcard = 0; @@ -935,8 +939,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) params.filter_ssids = NULL; } - if (wpa_s->wps) - wps_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); + extra_ie = wpa_supplicant_extra_ies(wpa_s); + if (extra_ie) { + params.extra_ies = wpabuf_head(extra_ie); + params.extra_ies_len = wpabuf_len(extra_ie); + } scan_params = ¶ms; @@ -953,7 +960,7 @@ scan: ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params, wpa_s->sched_scan_interval); - wpabuf_free(wps_ie); + wpabuf_free(extra_ie); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index c7187e4..b09e5f1 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -127,6 +127,15 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, "key management and encryption suites"); return; } + } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && + wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { + /* + * Both WPA and non-WPA IEEE 802.1X enabled in configuration - + * use non-WPA since the scan results did not indicate that the + * AP is using WPA or WPA2. + */ + wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); + wpa_s->sme.assoc_req_ie_len = 0; } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, @@ -802,7 +811,7 @@ static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s, return; } - params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int)); + params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); if (params->freqs == NULL) return; for (count = 0, i = 0; i < mode->num_channels; i++) { @@ -843,6 +852,8 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) const u8 *ie; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_ssid *ssid = wpa_s->current_ssid; + struct hostapd_hw_modes *hw_mode = NULL; + int i; eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL); wpa_s->sme.sched_obss_scan = 0; @@ -853,9 +864,20 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) ssid->mode != IEEE80211_MODE_INFRA) return; /* Not using station SME in wpa_supplicant */ - if (!wpa_s->hw.modes || - !(wpa_s->hw.modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) - return; /* Driver does not support HT40 */ + if (!wpa_s->hw.modes) + return; + + /* only HT caps in 11g mode are relevant */ + for (i = 0; i < wpa_s->hw.num_modes; i++) { + hw_mode = &wpa_s->hw.modes[i]; + if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G) + break; + } + + /* Driver does not support HT40 for 11g or doesn't have 11g. */ + if (i == wpa_s->hw.num_modes || !hw_mode || + !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) + return; if (bss == NULL || bss->freq < 2400 || bss->freq > 2500) return; /* Not associated on 2.4 GHz band */ @@ -938,9 +960,9 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx) sme_check_sa_query_timeout(wpa_s)) return; - nbuf = os_realloc(wpa_s->sme.sa_query_trans_id, - (wpa_s->sme.sa_query_count + 1) * - WLAN_SA_QUERY_TR_ID_LEN); + 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) return; if (wpa_s->sme.sa_query_count == 0) { diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c index 4448858..f60b182 100644 --- a/wpa_supplicant/tests/test_eap_sim_common.c +++ b/wpa_supplicant/tests/test_eap_sim_common.c @@ -28,7 +28,7 @@ static int test_eap_sim_prf(void) 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)) { + if (memcmp(w, buf, sizeof(w)) != 0) { printf("eap_sim_prf failed\n"); return 1; } diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c new file mode 100644 index 0000000..92ca536 --- /dev/null +++ b/wpa_supplicant/wifi_display.c @@ -0,0 +1,251 @@ +/* + * wpa_supplicant - Wi-Fi Display + * Copyright (c) 2011, Atheros Communications, Inc. + * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "p2p/p2p.h" +#include "common/ieee802_11_defs.h" +#include "wpa_supplicant_i.h" +#include "wifi_display.h" + + +int wifi_display_init(struct wpa_global *global) +{ + global->wifi_display = 1; + return 0; +} + + +void wifi_display_deinit(struct wpa_global *global) +{ + int i; + for (i = 0; i < MAX_WFD_SUBELEMS; i++) { + wpabuf_free(global->wfd_subelem[i]); + global->wfd_subelem[i] = NULL; + } +} + + +static int wifi_display_update_wfd_ie(struct wpa_global *global) +{ + struct wpabuf *ie, *buf; + size_t len, plen; + + wpa_printf(MSG_DEBUG, "WFD: Update WFD IE"); + + if (!global->wifi_display) { + wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not " + "include WFD IE"); + p2p_set_wfd_ie_beacon(global->p2p, NULL); + p2p_set_wfd_ie_probe_req(global->p2p, NULL); + p2p_set_wfd_ie_probe_resp(global->p2p, NULL); + p2p_set_wfd_ie_assoc_req(global->p2p, NULL); + p2p_set_wfd_ie_invitation(global->p2p, NULL); + p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL); + p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL); + p2p_set_wfd_ie_go_neg(global->p2p, NULL); + p2p_set_wfd_dev_info(global->p2p, NULL); + p2p_set_wfd_assoc_bssid(global->p2p, NULL); + p2p_set_wfd_coupled_sink_info(global->p2p, NULL); + return 0; + } + + p2p_set_wfd_dev_info(global->p2p, + global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); + p2p_set_wfd_assoc_bssid( + global->p2p, + global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]); + p2p_set_wfd_coupled_sink_info( + global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); + + /* + * WFD IE is included in number of management frames. Two different + * sets of subelements are included depending on the frame: + * + * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf, + * Provision Discovery Req: + * WFD Device Info + * [Associated BSSID] + * [Coupled Sink Info] + * + * Probe Request: + * WFD Device Info + * [Associated BSSID] + * [Coupled Sink Info] + * [WFD Extended Capability] + * + * Probe Response: + * WFD Device Info + * [Associated BSSID] + * [Coupled Sink Info] + * [WFD Extended Capability] + * [WFD Session Info] + * + * (Re)Association Response, P2P Invitation Req/Resp, + * Provision Discovery Resp: + * WFD Device Info + * [Associated BSSID] + * [Coupled Sink Info] + * [WFD Session Info] + */ + len = 0; + if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) + len += wpabuf_len(global->wfd_subelem[ + WFD_SUBELEM_DEVICE_INFO]); + if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) + len += wpabuf_len(global->wfd_subelem[ + WFD_SUBELEM_ASSOCIATED_BSSID]); + if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) + len += wpabuf_len(global->wfd_subelem[ + WFD_SUBELEM_COUPLED_SINK]); + if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) + len += wpabuf_len(global->wfd_subelem[ + WFD_SUBELEM_SESSION_INFO]); + if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) + len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); + buf = wpabuf_alloc(len); + if (buf == NULL) + return -1; + + if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) + wpabuf_put_buf(buf, + global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); + if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) + wpabuf_put_buf(buf, global->wfd_subelem[ + WFD_SUBELEM_ASSOCIATED_BSSID]); + if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) + wpabuf_put_buf(buf, + global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie); + p2p_set_wfd_ie_beacon(global->p2p, ie); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request", + ie); + p2p_set_wfd_ie_assoc_req(global->p2p, ie); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie); + p2p_set_wfd_ie_go_neg(global->p2p, ie); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " + "Request", ie); + p2p_set_wfd_ie_prov_disc_req(global->p2p, ie); + + plen = buf->used; + if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) + wpabuf_put_buf(buf, + global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie); + p2p_set_wfd_ie_probe_req(global->p2p, ie); + + if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) + wpabuf_put_buf(buf, + global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie); + p2p_set_wfd_ie_probe_resp(global->p2p, ie); + + /* Remove WFD Extended Capability from buffer */ + buf->used = plen; + if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) + wpabuf_put_buf(buf, + global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie); + p2p_set_wfd_ie_invitation(global->p2p, ie); + + ie = wifi_display_encaps(buf); + wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " + "Response", ie); + p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie); + + wpabuf_free(buf); + + return 0; +} + + +void wifi_display_enable(struct wpa_global *global, int enabled) +{ + wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s", + enabled ? "enabled" : "disabled"); + global->wifi_display = enabled; + wifi_display_update_wfd_ie(global); +} + + +int wifi_display_subelem_set(struct wpa_global *global, char *cmd) +{ + char *pos; + int subelem; + size_t len; + struct wpabuf *e; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + subelem = atoi(cmd); + if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) + return -1; + + len = os_strlen(pos); + if (len & 1) + return -1; + len /= 2; + + if (len == 0) { + /* Clear subelement */ + e = NULL; + wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem); + } else { + e = wpabuf_alloc(1 + len); + if (e == NULL) + return -1; + wpabuf_put_u8(e, subelem); + if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) { + wpabuf_free(e); + return -1; + } + wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem); + } + + wpabuf_free(global->wfd_subelem[subelem]); + global->wfd_subelem[subelem] = e; + wifi_display_update_wfd_ie(global); + + return 0; +} + + +int wifi_display_subelem_get(struct wpa_global *global, char *cmd, + char *buf, size_t buflen) +{ + int subelem; + + subelem = atoi(cmd); + if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) + return -1; + + if (global->wfd_subelem[subelem] == NULL) + return 0; + + return wpa_snprintf_hex(buf, buflen, + wpabuf_head_u8(global->wfd_subelem[subelem]) + + 1, + wpabuf_len(global->wfd_subelem[subelem]) - 1); +} diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h new file mode 100644 index 0000000..b75d4f2 --- /dev/null +++ b/wpa_supplicant/wifi_display.h @@ -0,0 +1,20 @@ +/* + * wpa_supplicant - Wi-Fi Display + * Copyright (c) 2011, Atheros Communications, Inc. + * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WIFI_DISPLAY_H +#define WIFI_DISPLAY_H + +int wifi_display_init(struct wpa_global *global); +void wifi_display_deinit(struct wpa_global *global); +void wifi_display_enable(struct wpa_global *global, int enabled); +int wifi_display_subelem_set(struct wpa_global *global, char *cmd); +int wifi_display_subelem_get(struct wpa_global *global, char *cmd, + char *buf, size_t buflen); + +#endif /* WIFI_DISPLAY_H */ diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c new file mode 100644 index 0000000..98ce966 --- /dev/null +++ b/wpa_supplicant/wnm_sta.c @@ -0,0 +1,248 @@ +/* + * wpa_supplicant - WNM + * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * + * 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 "rsn_supp/wpa.h" +#include "../wpa_supplicant/wpa_supplicant_i.h" +#include "../wpa_supplicant/driver_i.h" + +#define MAX_TFS_IE_LEN 1024 + +#ifdef CONFIG_IEEE80211V + +/* get the TFS IE from driver */ +static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, + u16 *buf_len, enum wnm_oper oper) +{ + wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); + + return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); +} + + +/* 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, + enum wnm_oper oper) +{ + wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); + + return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); +} + + +/* MLME-SLEEPMODE.request */ +int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, + u8 action, u8 intval) +{ + struct ieee80211_mgmt *mgmt; + int res; + size_t len; + struct wnm_sleep_element *wnmsleep_ie; + u8 *wnmtfs_ie; + u8 wnmsleep_ie_len; + u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ + enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : + WNM_SLEEP_TFS_REQ_IE_NONE; + + /* WNM-Sleep Mode IE */ + wnmsleep_ie_len = sizeof(struct wnm_sleep_element); + wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); + if (wnmsleep_ie == NULL) + return -1; + wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; + wnmsleep_ie->len = wnmsleep_ie_len - 2; + wnmsleep_ie->action_type = action; + wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; + wnmsleep_ie->intval = intval; + + /* TFS IE(s) */ + wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); + if (wnmtfs_ie == NULL) { + os_free(wnmsleep_ie); + return -1; + } + if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, + tfs_oper)) { + wnmtfs_ie_len = 0; + os_free(wnmtfs_ie); + wnmtfs_ie = NULL; + } + + mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); + if (mgmt == NULL) { + wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " + "WNM-Sleep Request action frame"); + return -1; + } + + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; + os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, + wnmsleep_ie_len); + /* copy TFS IE here */ + if (wnmtfs_ie_len > 0) { + os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + + wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); + } + + len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + + wnmtfs_ie_len; + + res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + &mgmt->u.action.category, len, 0); + if (res < 0) + wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " + "(action=%d, intval=%d)", action, intval); + + os_free(wnmsleep_ie); + os_free(wnmtfs_ie); + os_free(mgmt); + + return res; +} + + +static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, + const u8 *frm, int len) +{ + /* + * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data | + * WNM-Sleep Mode IE | TFS Response IE + */ + u8 *pos = (u8 *) frm; /* point to action field */ + u16 key_len_total = le_to_host16(*((u16 *)(frm+2))); + u8 gtk_len; +#ifdef CONFIG_IEEE80211W + u8 igtk_len; +#endif /* CONFIG_IEEE80211W */ + struct wnm_sleep_element *wnmsleep_ie = NULL; + /* multiple TFS Resp IE (assuming consecutive) */ + u8 *tfsresp_ie_start = NULL; + u8 *tfsresp_ie_end = NULL; + u16 tfsresp_ie_len = 0; + + wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d", + frm[0], frm[1], key_len_total); + pos += 4 + key_len_total; + while (pos - frm < len) { + u8 ie_len = *(pos + 1); + if (*pos == WLAN_EID_WNMSLEEP) + wnmsleep_ie = (struct wnm_sleep_element *) pos; + else if (*pos == WLAN_EID_TFS_RESP) { + if (!tfsresp_ie_start) + tfsresp_ie_start = pos; + tfsresp_ie_end = pos; + } else + wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); + pos += ie_len + 2; + } + + if (!wnmsleep_ie) { + wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); + return; + } + + if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT) { + wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " + "frame (action=%d, intval=%d)", + wnmsleep_ie->action_type, wnmsleep_ie->intval); + if (wnmsleep_ie->action_type == 0) { + wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, + wpa_s->bssid, NULL, NULL); + /* remove GTK/IGTK ?? */ + + /* set the TFS Resp IE(s) */ + if (tfsresp_ie_start && tfsresp_ie_end && + tfsresp_ie_end - tfsresp_ie_start >= 0) { + tfsresp_ie_len = (tfsresp_ie_end + + tfsresp_ie_end[1] + 2) - + tfsresp_ie_start; + wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); + /* + * 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, + WNM_SLEEP_TFS_RESP_IE_SET)) + wpa_printf(MSG_DEBUG, "Fail to set " + "TFS Resp IE"); + } + } else if (wnmsleep_ie->action_type == 1) { + wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, + wpa_s->bssid, NULL, NULL); + /* Install GTK/IGTK */ + do { + /* point to key data field */ + u8 *ptr = (u8 *) frm + 1 + 1 + 2; + while (ptr < (u8 *) frm + 4 + key_len_total) { + if (*ptr == WNM_SLEEP_SUBELEM_GTK) { + gtk_len = *(ptr + 4); + wpa_wnmsleep_install_key( + wpa_s->wpa, + WNM_SLEEP_SUBELEM_GTK, + ptr); + ptr += 13 + gtk_len; +#ifdef CONFIG_IEEE80211W + } else if (*ptr == + WNM_SLEEP_SUBELEM_IGTK) { + igtk_len = WPA_IGTK_LEN; + wpa_wnmsleep_install_key( + wpa_s->wpa, + WNM_SLEEP_SUBELEM_IGTK, + ptr); + ptr += 10 + WPA_IGTK_LEN; +#endif /* CONFIG_IEEE80211W */ + } else + break; /* skip the loop */ + } + } while(0); + } + } else { + wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " + "(action=%d, intval=%d)", + wnmsleep_ie->action_type, wnmsleep_ie->intval); + if (wnmsleep_ie->action_type == 0) + wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, + wpa_s->bssid, NULL, NULL); + else if (wnmsleep_ie->action_type == 1) + wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, + wpa_s->bssid, NULL, NULL); + } +} + + +void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, + struct rx_action *action) +{ + u8 *pos = (u8 *) action->data; /* point to action field */ + u8 act = *pos++; + /* u8 dialog_token = *pos++; */ + + switch (act) { + case WNM_SLEEP_MODE_RESP: + ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len); + break; + default: + break; + } +} + +#endif /* CONFIG_IEEE80211V */ diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h new file mode 100644 index 0000000..ba2535b --- /dev/null +++ b/wpa_supplicant/wnm_sta.h @@ -0,0 +1,21 @@ +/* + * IEEE 802.11v WNM related functions and structures + * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WNM_STA_H +#define WNM_STA_H + +struct rx_action; +struct wpa_supplicant; + +int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, + u8 action, u8 intval); + +void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, + struct rx_action *action); + +#endif /* WNM_STA_H */ diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index bed13dd..3986b9b 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -95,8 +95,11 @@ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ -static void print_help(void); +static void print_help(const char *cmd); static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); +static void wpa_cli_close_connection(void); +static char * wpa_cli_get_default_ifname(void); +static char ** wpa_list_cmd_list(void); static void usage(void) @@ -113,7 +116,7 @@ static void usage(void) " -B = run a daemon in the background\n" " default path: " CONFIG_CTRL_IFACE_DIR "\n" " default interface: first interface found in socket path\n"); - print_help(); + print_help(NULL); } @@ -241,7 +244,7 @@ static char ** cli_txt_list_array(struct dl_list *txt_list) char **res; struct cli_txt_entry *e; - res = os_zalloc((count + 1) * sizeof(char *)); + res = os_calloc(count + 1, sizeof(char *)); if (res == NULL) return NULL; @@ -364,6 +367,7 @@ static int wpa_cli_open_connection(const char *ifname, int attach) } else { printf("Warning: Failed to attach to " "wpa_supplicant.\n"); + wpa_cli_close_connection(); return -1; } } @@ -456,6 +460,58 @@ 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 (res < 0 || res >= end - pos) + goto fail; + pos += res; + + for (i = 0; i < argc; i++) { + res = os_snprintf(pos, end - pos, " %s", argv[i]); + if (res < 0 || res >= end - pos) + 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[]) +{ + char buf[256]; + if (argc < min_args) { + printf("Invalid %s command - at least %d argument%s " + "required.\n", cmd, min_args, + min_args > 1 ? "s are" : " is"); + return -1; + } + if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + +static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "IFNAME"); +} + + static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc > 0 && os_strcmp(argv[0], "verbose") == 0) @@ -480,14 +536,7 @@ static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int ret; - if (argc == 0) - return -1; - ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]); - if (ret < 0 || (size_t) ret >= sizeof(cmd)) - return -1; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv); } @@ -505,11 +554,26 @@ static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - print_help(); + print_help(argc > 0 ? argv[0] : NULL); return 0; } +static char ** wpa_cli_complete_help(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = wpa_list_cmd_list(); + break; + } + + return res; +} + + 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); @@ -577,21 +641,7 @@ static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid GET command: need one argument (variable " - "name)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long GET command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); } @@ -617,100 +667,34 @@ static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid PREAUTH command: needs one argument " - "(BSSID)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long PREAUTH command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv); } static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid AP_SCAN command: needs one argument (ap_scan " - "value)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long AP_SCAN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv); } static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid SCAN_INTERVAL command: needs one argument " - "scan_interval value)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "SCAN_INTERVAL %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long SCAN_INTERVAL command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv); } static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid BSS_EXPIRE_AGE command: needs one argument " - "(bss_expire_age value)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_AGE %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long BSS_EXPIRE_AGE command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv); } static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid BSS_EXPIRE_COUNT command: needs one argument " - "(bss_expire_count value)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_COUNT %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long BSS_EXPIRE_COUNT command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv); } @@ -734,69 +718,24 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid STKSTART command: needs one argument " - "(Peer STA MAC address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long STKSTART command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv); } static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid FT_DS command: needs one argument " - "(Target AP MAC address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long FT_DS command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv); } static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc == 0) { - /* Any BSSID */ - return wpa_ctrl_command(ctrl, "WPS_PBC"); - } - - /* Specific BSSID */ - res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_PBC command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv); } static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc == 0) { printf("Invalid WPS_PIN command: need one or two arguments:\n" "- BSSID: use 'any' to select any\n" @@ -805,49 +744,14 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) return -1; } - if (argc == 1) { - /* Use dynamically generated PIN (returned as reply) */ - res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_PIN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); - } - - /* Use hardcoded PIN from a label */ - res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_PIN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv); } static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1 && argc != 2) { - printf("Invalid WPS_CHECK_PIN command: needs one argument:\n" - "- PIN to be verified\n"); - return -1; - } - - if (argc == 2) - res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_CHECK_PIN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv); } @@ -861,9 +765,6 @@ static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, #ifdef CONFIG_WPS_OOB static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc != 3 && argc != 4) { printf("Invalid WPS_OOB command: need three or four " "arguments:\n" @@ -876,17 +777,7 @@ static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[]) return -1; } - if (argc == 3) - res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s", - argv[0], argv[1], argv[2]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s", - argv[0], argv[1], argv[2], argv[3]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_OOB command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv); } #endif /* CONFIG_WPS_OOB */ @@ -895,43 +786,14 @@ static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc >= 1) - res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC %s", - argv[0]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC"); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_NFC command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv); } static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid WPS_NFC_TOKEN command: need one argument:\n" - "format: WPS or NDEF\n"); - return -1; - } - if (argc >= 1) - res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", - argv[0]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN"); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_NFC_TOKEN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv); } @@ -1023,41 +885,14 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc < 1) { - printf("Invalid WPS_AP_PIN command: needs at least one " - "argument\n"); - return -1; - } - - if (argc > 2) - res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s %s", - argv[0], argv[1], argv[2]); - else if (argc > 1) - res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_AP_PIN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv); } static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[100]; - if (argc > 0) { - os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]); - return wpa_ctrl_command(ctrl, cmd); - } - return wpa_ctrl_command(ctrl, "WPS_ER_START"); + return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv); } @@ -1072,9 +907,6 @@ static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc < 2) { printf("Invalid WPS_ER_PIN command: need at least two " "arguments:\n" @@ -1084,48 +916,20 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc, return -1; } - if (argc > 2) - res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s", - argv[0], argv[1], argv[2]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_ER_PIN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv); } static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid WPS_ER_PBC command: need one argument:\n" - "- UUID: Specify the Enrollee\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_ER_PBC command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv); } static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc != 2) { printf("Invalid WPS_ER_LEARN command: need two arguments:\n" "- UUID: specify which AP to use\n" @@ -1133,22 +937,13 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, return -1; } - res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_ER_LEARN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv); } static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc != 2) { printf("Invalid WPS_ER_SET_CONFIG command: need two " "arguments:\n" @@ -1157,13 +952,7 @@ static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc, return -1; } - res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_SET_CONFIG %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_ER_SET_CONFIG command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv); } @@ -1222,9 +1011,6 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc != 2) { printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two " "arguments:\n" @@ -1233,53 +1019,20 @@ static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc, return -1; } - res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_NFC_CONFIG_TOKEN %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_ER_NFC_CONFIG_TOKEN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv); } #endif /* CONFIG_WPS_NFC */ static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid IBSS_RSN command: needs one argument " - "(Peer STA MAC address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long IBSS_RSN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv); } static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid LEVEL command: needs one argument (debug " - "level)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long LEVEL command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv); } @@ -1484,85 +1237,25 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256], *pos, *end; - int i, ret; - if (argc < 2) { printf("Invalid BSSID command: needs two arguments (network " "id and BSSID)\n"); return -1; } - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, "BSSID"); - if (ret < 0 || ret >= end - pos) { - printf("Too long BSSID command.\n"); - return -1; - } - pos += ret; - for (i = 0; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (ret < 0 || ret >= end - pos) { - printf("Too long BSSID command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv); } static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256], *pos, *end; - int i, ret; - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, "BLACKLIST"); - if (ret < 0 || ret >= end - pos) { - printf("Too long BLACKLIST command.\n"); - return -1; - } - pos += ret; - for (i = 0; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (ret < 0 || ret >= end - pos) { - printf("Too long BLACKLIST command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv); } static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256], *pos, *end; - int i, ret; - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, "LOG_LEVEL"); - if (ret < 0 || ret >= end - pos) { - printf("Too long LOG_LEVEL command.\n"); - return -1; - } - pos += ret; - for (i = 0; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (ret < 0 || ret >= end - pos) { - printf("Too long LOG_LEVEL command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv); } @@ -1576,68 +1269,21 @@ static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[32]; - int res; - - if (argc < 1) { - printf("Invalid SELECT_NETWORK command: needs one argument " - "(network id)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv); } static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[32]; - int res; - - if (argc < 1) { - printf("Invalid ENABLE_NETWORK command: needs one argument " - "(network id)\n"); - return -1; - } - - if (argc > 1) - res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv); } static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[32]; - int res; - - if (argc < 1) { - printf("Invalid DISABLE_NETWORK command: needs one argument " - "(network id)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv); } @@ -1651,21 +1297,7 @@ static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[32]; - int res; - - if (argc < 1) { - printf("Invalid REMOVE_NETWORK command: needs one argument " - "(network id)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); } @@ -1693,9 +1325,6 @@ static void wpa_cli_show_network_variables(void) static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc == 0) { wpa_cli_show_network_variables(); return 0; @@ -1707,22 +1336,13 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, return -1; } - res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s", - argv[0], argv[1], argv[2]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long SET_NETWORK command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv); } static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc == 0) { wpa_cli_show_network_variables(); return 0; @@ -1734,13 +1354,7 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, return -1; } - res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long GET_NETWORK command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv); } @@ -1760,42 +1374,19 @@ static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[32]; - int res; - - if (argc < 1) { - printf("Invalid REMOVE_CRED command: needs one argument " - "(cred id)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); } static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc != 3) { printf("Invalid SET_CRED command: needs three arguments\n" "(cred id, variable name, and value)\n"); return -1; } - res = os_snprintf(cmd, sizeof(cmd), "SET_CRED %s %s %s", - argv[0], argv[1], argv[2]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long SET_CRED command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv); } @@ -1835,24 +1426,7 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[64]; - int res; - - if (argc < 1) { - printf("Invalid BSS command: need at least one argument" - "(index or BSSID)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "BSS %s%s%s%s%s", argv[0], - argc > 1 ? " " : "", argc > 1 ? argv[1] : "", - argc > 2 ? " " : "", argc > 2 ? argv[2] : ""); - - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv); } @@ -1874,9 +1448,6 @@ static char ** wpa_cli_complete_bss(const char *str, int pos) static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[64]; - int res; - if (argc < 1 || argc > 2) { printf("Invalid GET_CAPABILITY command: need either one or " "two arguments\n"); @@ -1889,13 +1460,7 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, return -1; } - res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0], - (argc == 2) ? " strict" : ""); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv); } @@ -1975,20 +1540,7 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc != 1) { - printf("Invalid INTERFACE_REMOVE command: needs one argument " - "(interface name)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv); } @@ -2002,14 +1554,7 @@ static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, #ifdef CONFIG_AP static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char buf[64]; - if (argc != 1) { - printf("Invalid 'sta' command - exactly one argument, STA " - "address, is required.\n"); - return -1; - } - os_snprintf(buf, sizeof(buf), "STA %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); + return wpa_cli_cmd(ctrl, "STA", 1, argc, argv); } @@ -2066,36 +1611,14 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char buf[64]; - if (argc < 1) { - printf("Invalid 'deauthenticate' command - exactly one " - "argument, STA address, is required.\n"); - return -1; - } - if (argc > 1) - os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", - argv[0], argv[1]); - else - os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); + return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv); } static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char buf[64]; - if (argc < 1) { - printf("Invalid 'disassociate' command - exactly one " - "argument, STA address, is required.\n"); - return -1; - } - if (argc > 1) - os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", - argv[0], argv[1]); - else - os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); + return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv); } #endif /* CONFIG_AP */ @@ -2120,21 +1643,7 @@ static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc != 1) { - printf("Invalid ROAM command: needs one argument " - "(target AP's BSSID)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long ROAM command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv); } @@ -2142,24 +1651,36 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; + return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv); +} - if (argc == 0) - return wpa_ctrl_command(ctrl, "P2P_FIND"); - if (argc > 2) - res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s %s", - argv[0], argv[1], argv[2]); - else if (argc > 1) - res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); +static char ** wpa_cli_complete_p2p_find(const char *str, int pos) +{ + char **res = NULL; + int arg = get_cmd_arg_num(str, pos); + + res = os_calloc(6, sizeof(char *)); + if (res == NULL) + return NULL; + res[0] = os_strdup("type=social"); + if (res[0] == NULL) { + os_free(res); + return NULL; + } + res[1] = os_strdup("type=progressive"); + if (res[1] == NULL) + return res; + res[2] = os_strdup("delay="); + if (res[2] == NULL) + return res; + res[3] = os_strdup("dev_id="); + if (res[3] == NULL) + return res; + if (arg == 1) + res[4] = os_strdup("[timeout]"); + + return res; } @@ -2173,40 +1694,7 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc < 2) { - printf("Invalid P2P_CONNECT command: needs at least two " - "arguments (address and pbc/PIN)\n"); - return -1; - } -#ifdef ANDROID_P2P - if (argc > 5) - res = os_snprintf(cmd, sizeof(cmd), - "P2P_CONNECT %s %s %s %s %s %s", - argv[0], argv[1], argv[2], argv[3], - argv[4], argv[5]); - else -#endif - if (argc > 4) - res = os_snprintf(cmd, sizeof(cmd), - "P2P_CONNECT %s %s %s %s %s", - argv[0], argv[1], argv[2], argv[3], - argv[4]); - else if (argc > 3) - res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s %s", - argv[0], argv[1], argv[2], argv[3]); - else if (argc > 2) - res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s", - argv[0], argv[1], argv[2]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv); } @@ -2228,37 +1716,14 @@ static char ** wpa_cli_complete_p2p_connect(const char *str, int pos) static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc == 0) - return wpa_ctrl_command(ctrl, "P2P_LISTEN"); - - res = os_snprintf(cmd, sizeof(cmd), "P2P_LISTEN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv); } static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc != 1) { - printf("Invalid P2P_GROUP_REMOVE command: needs one argument " - "(interface name)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv); } @@ -2280,31 +1745,13 @@ static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos) static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc == 0) - return wpa_ctrl_command(ctrl, "P2P_GROUP_ADD"); - - if (argc > 1) - res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv); } static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - if (argc != 2 && argc != 3) { printf("Invalid P2P_PROV_DISC command: needs at least " "two arguments, address and config method\n" @@ -2312,16 +1759,7 @@ static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, return -1; } - if (argc == 3) - res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s", - argv[0], argv[1], argv[2]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv); } @@ -2336,7 +1774,6 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[4096]; - int res; if (argc != 2 && argc != 4) { printf("Invalid P2P_SERV_DISC_REQ command: needs two " @@ -2346,16 +1783,8 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, return -1; } - if (argc == 4) - res = os_snprintf(cmd, sizeof(cmd), - "P2P_SERV_DISC_REQ %s %s %s %s", - argv[0], argv[1], argv[2], argv[3]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd)) + if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0) return -1; - cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } @@ -2363,21 +1792,7 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc != 1) { - printf("Invalid P2P_SERV_DISC_CANCEL_REQ command: needs one " - "argument (pending request identifier)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_CANCEL_REQ %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv); } @@ -2412,21 +1827,7 @@ static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc != 1) { - printf("Invalid P2P_SERV_DISC_EXTERNAL command: needs one " - "argument (external processing: 0/1)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_EXTERNAL %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv); } @@ -2494,60 +1895,20 @@ static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc != 1) { - printf("Invalid P2P_REJECT command: needs one argument " - "(peer address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "P2P_REJECT %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv); } static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[128]; - int res; - - if (argc < 1) { - printf("Invalid P2P_INVITE command: needs at least one " - "argument\n"); - return -1; - } - - if (argc > 2) - res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s %s", - argv[0], argv[1], argv[2]); - else if (argc > 1) - res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv); } static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char buf[64]; - if (argc != 1) { - printf("Invalid 'p2p_peer' command - exactly one argument, " - "P2P peer device address, is required.\n"); - return -1; - } - os_snprintf(buf, sizeof(buf), "P2P_PEER %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); + return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv); } @@ -2623,20 +1984,7 @@ static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[100]; - int res; - - if (argc != 2) { - printf("Invalid P2P_SET command: needs two arguments (field, " - "value)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "P2P_SET %s %s", argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv); } @@ -2656,48 +2004,58 @@ static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[100]; - int res; + return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv); +} - if (argc != 1) { - printf("Invalid P2P_UNAUTHORIZE command: needs one argument " - "(peer address)\n"); + +static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 0 && argc != 2 && argc != 4) { + printf("Invalid P2P_PRESENCE_REQ command: needs two arguments " + "(preferred duration, interval; in microsecods).\n" + "Optional second pair can be used to provide " + "acceptable values.\n"); return -1; } - res = os_snprintf(cmd, sizeof(cmd), "P2P_UNAUTHORIZE %s", argv[0]); + return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv); +} - if (res < 0 || (size_t) res >= sizeof(cmd)) + +static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 0 && argc != 2) { + printf("Invalid P2P_EXT_LISTEN command: needs two arguments " + "(availability period, availability interval; in " + "millisecods).\n" + "Extended Listen Timing can be cancelled with this " + "command when used without parameters.\n"); return -1; + } - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv); } +#endif /* CONFIG_P2P */ -static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, - char *argv[]) +#ifdef CONFIG_WIFI_DISPLAY + +static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc, + char *argv[]) { char cmd[100]; int res; - if (argc != 0 && argc != 2 && argc != 4) { - printf("Invalid P2P_PRESENCE_REQ command: needs two arguments " - "(preferred duration, interval; in microsecods).\n" - "Optional second pair can be used to provide " - "acceptable values.\n"); + if (argc != 1 && argc != 2) { + printf("Invalid WFD_SUBELEM_SET command: needs one or two " + "arguments (subelem, hexdump)\n"); return -1; } - if (argc == 4) - res = os_snprintf(cmd, sizeof(cmd), - "P2P_PRESENCE_REQ %s %s %s %s", - argv[0], argv[1], argv[2], argv[3]); - else if (argc == 2) - res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ"); + res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s", + argv[0], argc > 1 ? argv[1] : ""); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; @@ -2705,33 +2063,26 @@ static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, } -static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc, - char *argv[]) +static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) { char cmd[100]; int res; - if (argc != 0 && argc != 2) { - printf("Invalid P2P_EXT_LISTEN command: needs two arguments " - "(availability period, availability interval; in " - "millisecods).\n" - "Extended Listen Timing can be cancelled with this " - "command when used without parameters.\n"); + if (argc != 1) { + printf("Invalid WFD_SUBELEM_GET command: needs one " + "argument (subelem)\n"); return -1; } - if (argc == 2) - res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN"); + res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s", + argv[0]); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } - -#endif /* CONFIG_P2P */ +#endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING @@ -2752,58 +2103,34 @@ static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[100]; - int res; - - if (argc == 0) - return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT"); - - res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv); } static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[100]; - int res; + return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv); +} - if (argc != 1) { - printf("Invalid INTERWORKING_CONNECT commands: needs one " - "argument (BSSID)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); +static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); } -static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc, + char *argv[]) { - char cmd[100]; - int res; + return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv); +} - if (argc != 2) { - printf("Invalid ANQP_GET command: needs two arguments " - "(addr and info id list)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); +static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv); } #endif /* CONFIG_INTERWORKING */ @@ -2813,21 +2140,7 @@ static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[100]; - int res; - - if (argc != 2) { - printf("Invalid HS20_ANQP_GET command: needs two arguments " - "(addr and subtype list)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "HS20_ANQP_GET %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv); } @@ -2835,7 +2148,6 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[512]; - int res; if (argc == 0) { printf("Command needs one or two arguments (dst mac addr and " @@ -2843,18 +2155,9 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, return -1; } - if (argc == 1) - res = os_snprintf(cmd, sizeof(cmd), - "HS20_GET_NAI_HOME_REALM_LIST %s", - argv[0]); - else - res = os_snprintf(cmd, sizeof(cmd), - "HS20_GET_NAI_HOME_REALM_LIST %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long command.\n"); + if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST", + argc, argv) < 0) return -1; - } return wpa_ctrl_command(ctrl, cmd); } @@ -2865,83 +2168,28 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid STA_AUTOCONNECT command: needs one argument " - "(0/1 = disable/enable automatic reconnection)\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "STA_AUTOCONNECT %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long STA_AUTOCONNECT command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv); } static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid TDLS_DISCOVER command: needs one argument " - "(Peer STA MAC address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "TDLS_DISCOVER %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long TDLS_DISCOVER command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv); } static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid TDLS_SETUP command: needs one argument " - "(Peer STA MAC address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "TDLS_SETUP %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long TDLS_SETUP command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv); } static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid TDLS_TEARDOWN command: needs one argument " - "(Peer STA MAC address)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long TDLS_TEARDOWN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv); } @@ -2970,24 +2218,23 @@ static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - char cmd[256]; - int res; - if (argc == 0) return wpa_ctrl_command(ctrl, "AUTOSCAN "); - res = os_snprintf(cmd, sizeof(cmd), "AUTOSCAN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long AUTOSCAN command.\n"); - return -1; - } - - return wpa_ctrl_command(ctrl, cmd); + return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv); } #endif /* CONFIG_AUTOSCAN */ +static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc == 0) + return -1; + return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); +} + + #ifdef ANDROID static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -3009,6 +2256,7 @@ static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) } #endif + enum wpa_cli_cmd_flags { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 @@ -3017,401 +2265,433 @@ enum wpa_cli_cmd_flags { struct wpa_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); + char ** (*completion)(const char *str, int pos); enum wpa_cli_cmd_flags flags; const char *usage; }; static struct wpa_cli_cmd wpa_cli_commands[] = { - { "status", wpa_cli_cmd_status, + { "status", wpa_cli_cmd_status, NULL, cli_cmd_flag_none, "[verbose] = get current WPA/EAPOL/EAP status" }, - { "ping", wpa_cli_cmd_ping, + { "ifname", wpa_cli_cmd_ifname, NULL, + cli_cmd_flag_none, + "= get current interface name" }, + { "ping", wpa_cli_cmd_ping, NULL, cli_cmd_flag_none, "= pings wpa_supplicant" }, - { "relog", wpa_cli_cmd_relog, + { "relog", wpa_cli_cmd_relog, NULL, cli_cmd_flag_none, "= re-open log-file (allow rolling logs)" }, - { "note", wpa_cli_cmd_note, + { "note", wpa_cli_cmd_note, NULL, cli_cmd_flag_none, "<text> = add a note to wpa_supplicant debug log" }, - { "mib", wpa_cli_cmd_mib, + { "mib", wpa_cli_cmd_mib, NULL, cli_cmd_flag_none, "= get MIB variables (dot1x, dot11)" }, - { "help", wpa_cli_cmd_help, + { "help", wpa_cli_cmd_help, wpa_cli_complete_help, cli_cmd_flag_none, - "= show this usage help" }, - { "interface", wpa_cli_cmd_interface, + "[command] = show usage help" }, + { "interface", wpa_cli_cmd_interface, NULL, cli_cmd_flag_none, "[ifname] = show interfaces/select interface" }, - { "level", wpa_cli_cmd_level, + { "level", wpa_cli_cmd_level, NULL, cli_cmd_flag_none, "<debug level> = change debug level" }, - { "license", wpa_cli_cmd_license, + { "license", wpa_cli_cmd_license, NULL, cli_cmd_flag_none, "= show full wpa_cli license" }, - { "quit", wpa_cli_cmd_quit, + { "quit", wpa_cli_cmd_quit, NULL, cli_cmd_flag_none, "= exit wpa_cli" }, - { "set", wpa_cli_cmd_set, + { "set", wpa_cli_cmd_set, NULL, cli_cmd_flag_none, "= set variables (shows list of variables when run without " "arguments)" }, - { "get", wpa_cli_cmd_get, + { "get", wpa_cli_cmd_get, NULL, cli_cmd_flag_none, "<name> = get information" }, - { "logon", wpa_cli_cmd_logon, + { "logon", wpa_cli_cmd_logon, NULL, cli_cmd_flag_none, "= IEEE 802.1X EAPOL state machine logon" }, - { "logoff", wpa_cli_cmd_logoff, + { "logoff", wpa_cli_cmd_logoff, NULL, cli_cmd_flag_none, "= IEEE 802.1X EAPOL state machine logoff" }, - { "pmksa", wpa_cli_cmd_pmksa, + { "pmksa", wpa_cli_cmd_pmksa, NULL, cli_cmd_flag_none, "= show PMKSA cache" }, - { "reassociate", wpa_cli_cmd_reassociate, + { "reassociate", wpa_cli_cmd_reassociate, NULL, cli_cmd_flag_none, "= force reassociation" }, - { "preauthenticate", wpa_cli_cmd_preauthenticate, + { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss, cli_cmd_flag_none, "<BSSID> = force preauthentication" }, - { "identity", wpa_cli_cmd_identity, + { "identity", wpa_cli_cmd_identity, NULL, cli_cmd_flag_none, "<network id> <identity> = configure identity for an SSID" }, - { "password", wpa_cli_cmd_password, + { "password", wpa_cli_cmd_password, NULL, cli_cmd_flag_sensitive, "<network id> <password> = configure password for an SSID" }, - { "new_password", wpa_cli_cmd_new_password, + { "new_password", wpa_cli_cmd_new_password, NULL, cli_cmd_flag_sensitive, "<network id> <password> = change password for an SSID" }, - { "pin", wpa_cli_cmd_pin, + { "pin", wpa_cli_cmd_pin, NULL, cli_cmd_flag_sensitive, "<network id> <pin> = configure pin for an SSID" }, - { "otp", wpa_cli_cmd_otp, + { "otp", wpa_cli_cmd_otp, NULL, cli_cmd_flag_sensitive, "<network id> <password> = configure one-time-password for an SSID" }, - { "passphrase", wpa_cli_cmd_passphrase, + { "passphrase", wpa_cli_cmd_passphrase, NULL, cli_cmd_flag_sensitive, "<network id> <passphrase> = configure private key passphrase\n" " for an SSID" }, - { "bssid", wpa_cli_cmd_bssid, + { "bssid", wpa_cli_cmd_bssid, NULL, cli_cmd_flag_none, "<network id> <BSSID> = set preferred BSSID for an SSID" }, - { "blacklist", wpa_cli_cmd_blacklist, + { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss, cli_cmd_flag_none, "<BSSID> = add a BSSID to the blacklist\n" "blacklist clear = clear the blacklist\n" "blacklist = display the blacklist" }, - { "log_level", wpa_cli_cmd_log_level, + { "log_level", wpa_cli_cmd_log_level, NULL, cli_cmd_flag_none, "<level> [<timestamp>] = update the log level/timestamp\n" "log_level = display the current log level and log options" }, - { "list_networks", wpa_cli_cmd_list_networks, + { "list_networks", wpa_cli_cmd_list_networks, NULL, cli_cmd_flag_none, "= list configured networks" }, - { "select_network", wpa_cli_cmd_select_network, + { "select_network", wpa_cli_cmd_select_network, NULL, cli_cmd_flag_none, "<network id> = select a network (disable others)" }, - { "enable_network", wpa_cli_cmd_enable_network, + { "enable_network", wpa_cli_cmd_enable_network, NULL, cli_cmd_flag_none, "<network id> = enable a network" }, - { "disable_network", wpa_cli_cmd_disable_network, + { "disable_network", wpa_cli_cmd_disable_network, NULL, cli_cmd_flag_none, "<network id> = disable a network" }, - { "add_network", wpa_cli_cmd_add_network, + { "add_network", wpa_cli_cmd_add_network, NULL, cli_cmd_flag_none, "= add a network" }, - { "remove_network", wpa_cli_cmd_remove_network, + { "remove_network", wpa_cli_cmd_remove_network, NULL, cli_cmd_flag_none, "<network id> = remove a network" }, - { "set_network", wpa_cli_cmd_set_network, + { "set_network", wpa_cli_cmd_set_network, NULL, cli_cmd_flag_sensitive, "<network id> <variable> <value> = set network variables (shows\n" " list of variables when run without arguments)" }, - { "get_network", wpa_cli_cmd_get_network, + { "get_network", wpa_cli_cmd_get_network, NULL, cli_cmd_flag_none, "<network id> <variable> = get network variables" }, - { "list_creds", wpa_cli_cmd_list_creds, + { "list_creds", wpa_cli_cmd_list_creds, NULL, cli_cmd_flag_none, "= list configured credentials" }, - { "add_cred", wpa_cli_cmd_add_cred, + { "add_cred", wpa_cli_cmd_add_cred, NULL, cli_cmd_flag_none, "= add a credential" }, - { "remove_cred", wpa_cli_cmd_remove_cred, + { "remove_cred", wpa_cli_cmd_remove_cred, NULL, cli_cmd_flag_none, "<cred id> = remove a credential" }, - { "set_cred", wpa_cli_cmd_set_cred, + { "set_cred", wpa_cli_cmd_set_cred, NULL, cli_cmd_flag_sensitive, "<cred id> <variable> <value> = set credential variables" }, - { "save_config", wpa_cli_cmd_save_config, + { "save_config", wpa_cli_cmd_save_config, NULL, cli_cmd_flag_none, "= save the current configuration" }, - { "disconnect", wpa_cli_cmd_disconnect, + { "disconnect", wpa_cli_cmd_disconnect, NULL, cli_cmd_flag_none, "= disconnect and wait for reassociate/reconnect command before\n" " connecting" }, - { "reconnect", wpa_cli_cmd_reconnect, + { "reconnect", wpa_cli_cmd_reconnect, NULL, cli_cmd_flag_none, "= like reassociate, but only takes effect if already disconnected" }, - { "scan", wpa_cli_cmd_scan, + { "scan", wpa_cli_cmd_scan, NULL, cli_cmd_flag_none, "= request new BSS scan" }, - { "scan_results", wpa_cli_cmd_scan_results, + { "scan_results", wpa_cli_cmd_scan_results, NULL, cli_cmd_flag_none, "= get latest scan results" }, - { "bss", wpa_cli_cmd_bss, + { "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, + { "get_capability", wpa_cli_cmd_get_capability, NULL, cli_cmd_flag_none, - "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels>\n" - " = get capabilities" }, - { "reconfigure", wpa_cli_cmd_reconfigure, + "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> " + "= get capabilies" }, + { "reconfigure", wpa_cli_cmd_reconfigure, NULL, cli_cmd_flag_none, "= force wpa_supplicant to re-read its configuration file" }, - { "terminate", wpa_cli_cmd_terminate, + { "terminate", wpa_cli_cmd_terminate, NULL, cli_cmd_flag_none, "= terminate wpa_supplicant" }, - { "interface_add", wpa_cli_cmd_interface_add, + { "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" }, - { "interface_remove", wpa_cli_cmd_interface_remove, + { "interface_remove", wpa_cli_cmd_interface_remove, NULL, cli_cmd_flag_none, "<ifname> = removes the interface" }, - { "interface_list", wpa_cli_cmd_interface_list, + { "interface_list", wpa_cli_cmd_interface_list, NULL, cli_cmd_flag_none, "= list available interfaces" }, - { "ap_scan", wpa_cli_cmd_ap_scan, + { "ap_scan", wpa_cli_cmd_ap_scan, NULL, cli_cmd_flag_none, "<value> = set ap_scan parameter" }, - { "scan_interval", wpa_cli_cmd_scan_interval, + { "scan_interval", wpa_cli_cmd_scan_interval, NULL, cli_cmd_flag_none, "<value> = set scan_interval parameter (in seconds)" }, - { "bss_expire_age", wpa_cli_cmd_bss_expire_age, + { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL, cli_cmd_flag_none, "<value> = set BSS expiration age parameter" }, - { "bss_expire_count", wpa_cli_cmd_bss_expire_count, + { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL, cli_cmd_flag_none, "<value> = set BSS expiration scan count parameter" }, - { "bss_flush", wpa_cli_cmd_bss_flush, + { "bss_flush", wpa_cli_cmd_bss_flush, NULL, cli_cmd_flag_none, "<value> = set BSS flush age (0 by default)" }, - { "stkstart", wpa_cli_cmd_stkstart, + { "stkstart", wpa_cli_cmd_stkstart, NULL, cli_cmd_flag_none, "<addr> = request STK negotiation with <addr>" }, - { "ft_ds", wpa_cli_cmd_ft_ds, + { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss, cli_cmd_flag_none, "<addr> = request over-the-DS FT with <addr>" }, - { "wps_pbc", wpa_cli_cmd_wps_pbc, + { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss, cli_cmd_flag_none, "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, - { "wps_pin", wpa_cli_cmd_wps_pin, + { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss, cli_cmd_flag_sensitive, "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not " "hardcoded)" }, - { "wps_check_pin", wpa_cli_cmd_wps_check_pin, + { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL, cli_cmd_flag_sensitive, "<PIN> = verify PIN checksum" }, - { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none, + { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none, "Cancels the pending WPS operation" }, #ifdef CONFIG_WPS_OOB - { "wps_oob", wpa_cli_cmd_wps_oob, + { "wps_oob", wpa_cli_cmd_wps_oob, NULL, cli_cmd_flag_sensitive, "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" }, #endif /* CONFIG_WPS_OOB */ #ifdef CONFIG_WPS_NFC - { "wps_nfc", wpa_cli_cmd_wps_nfc, + { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss, cli_cmd_flag_none, "[BSSID] = start Wi-Fi Protected Setup: NFC" }, - { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, + { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL, cli_cmd_flag_none, "<WPS|NDEF> = create password token" }, - { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, + { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL, cli_cmd_flag_sensitive, "<hexdump of payload> = report read NFC tag with WPS data" }, #endif /* CONFIG_WPS_NFC */ - { "wps_reg", wpa_cli_cmd_wps_reg, + { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss, cli_cmd_flag_sensitive, "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" }, - { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, + { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL, cli_cmd_flag_sensitive, "[params..] = enable/disable AP PIN" }, - { "wps_er_start", wpa_cli_cmd_wps_er_start, + { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL, cli_cmd_flag_none, "[IP address] = start Wi-Fi Protected Setup External Registrar" }, - { "wps_er_stop", wpa_cli_cmd_wps_er_stop, + { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL, cli_cmd_flag_none, "= stop Wi-Fi Protected Setup External Registrar" }, - { "wps_er_pin", wpa_cli_cmd_wps_er_pin, + { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL, cli_cmd_flag_sensitive, "<UUID> <PIN> = add an Enrollee PIN to External Registrar" }, - { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, + { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL, cli_cmd_flag_none, "<UUID> = accept an Enrollee PBC using External Registrar" }, - { "wps_er_learn", wpa_cli_cmd_wps_er_learn, + { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL, cli_cmd_flag_sensitive, "<UUID> <PIN> = learn AP configuration" }, - { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, + { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL, cli_cmd_flag_none, "<UUID> <network id> = set AP configuration for enrolling" }, - { "wps_er_config", wpa_cli_cmd_wps_er_config, + { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL, cli_cmd_flag_sensitive, "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" }, #ifdef CONFIG_WPS_NFC - { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, + { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL, cli_cmd_flag_none, "<WPS/NDEF> <UUID> = build NFC configuration token" }, #endif /* CONFIG_WPS_NFC */ - { "ibss_rsn", wpa_cli_cmd_ibss_rsn, + { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL, cli_cmd_flag_none, "<addr> = request RSN authentication with <addr> in IBSS" }, #ifdef CONFIG_AP - { "sta", wpa_cli_cmd_sta, + { "sta", wpa_cli_cmd_sta, NULL, cli_cmd_flag_none, "<addr> = get information about an associated station (AP)" }, - { "all_sta", wpa_cli_cmd_all_sta, + { "all_sta", wpa_cli_cmd_all_sta, NULL, cli_cmd_flag_none, "= get information about all associated stations (AP)" }, - { "deauthenticate", wpa_cli_cmd_deauthenticate, + { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL, cli_cmd_flag_none, "<addr> = deauthenticate a station" }, - { "disassociate", wpa_cli_cmd_disassociate, + { "disassociate", wpa_cli_cmd_disassociate, NULL, cli_cmd_flag_none, "<addr> = disassociate a station" }, #endif /* CONFIG_AP */ - { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none, + { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, "= notification of suspend/hibernate" }, - { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none, + { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none, "= notification of resume/thaw" }, - { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none, + { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none, "= drop SA without deauth/disassoc (test command)" }, - { "roam", wpa_cli_cmd_roam, + { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, cli_cmd_flag_none, "<addr> = roam to the specified BSS" }, #ifdef CONFIG_P2P - { "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none, + { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, + cli_cmd_flag_none, "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" }, - { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, cli_cmd_flag_none, + { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none, "= stop P2P Devices search" }, - { "p2p_connect", wpa_cli_cmd_p2p_connect, cli_cmd_flag_none, - "<addr> <\"pbc\"|PIN> = connect to a P2P Devices" }, - { "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none, + { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect, + cli_cmd_flag_none, + "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" }, + { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none, "[timeout] = listen for P2P Devices for up-to timeout seconds" }, - { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none, + { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, + wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none, "<ifname> = remove P2P group interface (terminate group if GO)" }, - { "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none, - "= add a new P2P group (local end as GO)" }, - { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none, + { "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_prov_disc", wpa_cli_cmd_p2p_prov_disc, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "<addr> <method> = request provisioning discovery" }, - { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, + { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL, cli_cmd_flag_none, "= get the passphrase for a group (GO only)" }, { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req, - cli_cmd_flag_none, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "<addr> <TLVs> = schedule service discovery request" }, { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req, - cli_cmd_flag_none, + NULL, cli_cmd_flag_none, "<id> = cancel pending service discovery request" }, - { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, + { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL, cli_cmd_flag_none, "<freq> <addr> <dialog token> <TLVs> = service discovery response" }, - { "p2p_service_update", wpa_cli_cmd_p2p_service_update, + { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL, cli_cmd_flag_none, "= indicate change in local services" }, - { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, + { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL, cli_cmd_flag_none, "<external> = set external processing of service discovery" }, - { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, + { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL, cli_cmd_flag_none, "= remove all stored service entries" }, - { "p2p_service_add", wpa_cli_cmd_p2p_service_add, + { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL, cli_cmd_flag_none, "<bonjour|upnp> <query|version> <response|service> = add a local " "service" }, - { "p2p_service_del", wpa_cli_cmd_p2p_service_del, + { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL, cli_cmd_flag_none, "<bonjour|upnp> <query|version> [|service] = remove a local " "service" }, - { "p2p_reject", wpa_cli_cmd_p2p_reject, + { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "<addr> = reject connection attempts from a specific peer" }, - { "p2p_invite", wpa_cli_cmd_p2p_invite, + { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL, cli_cmd_flag_none, "<cmd> [peer=addr] = invite peer" }, - { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none, + { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none, "[discovered] = list known (optionally, only fully discovered) P2P " "peers" }, - { "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none, + { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer, + cli_cmd_flag_none, "<address> = show information about known P2P peer" }, - { "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none, + { "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none, "<field> <value> = set a P2P parameter" }, - { "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none, + { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none, "= flush P2P state" }, - { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none, + { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none, "= cancel P2P group formation" }, - { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none, + { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "<address> = unauthorize a peer" }, - { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none, + { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL, + cli_cmd_flag_none, "[<duration> <interval>] [<duration> <interval>] = request GO " "presence" }, - { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none, + { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL, + cli_cmd_flag_none, "[<period> <interval>] = set extended listen timing" }, #endif /* CONFIG_P2P */ - +#ifdef CONFIG_WIFI_DISPLAY + { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL, + cli_cmd_flag_none, + "<subelem> [contents] = set Wi-Fi Display subelement" }, + { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL, + cli_cmd_flag_none, + "<subelem> = get Wi-Fi Display subelement" }, +#endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING - { "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none, + { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none, "= fetch ANQP information for all APs" }, - { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none, + { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL, + cli_cmd_flag_none, "= stop fetch_anqp operation" }, - { "interworking_select", wpa_cli_cmd_interworking_select, + { "interworking_select", wpa_cli_cmd_interworking_select, NULL, cli_cmd_flag_none, "[auto] = perform Interworking network selection" }, { "interworking_connect", wpa_cli_cmd_interworking_connect, - cli_cmd_flag_none, + wpa_cli_complete_bss, cli_cmd_flag_none, "<BSSID> = connect using Interworking credentials" }, - { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none, + { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, + cli_cmd_flag_none, "<addr> <info id>[,<info id>]... = request ANQP information" }, + { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss, + cli_cmd_flag_none, + "<addr> <AdvProtoID> [QueryReq] = GAS request" }, + { "gas_response_get", wpa_cli_cmd_gas_response_get, + wpa_cli_complete_bss, cli_cmd_flag_none, + "<addr> <dialog token> [start,len] = Fetch last GAS response" }, #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 - { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, cli_cmd_flag_none, + { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss, + cli_cmd_flag_none, "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information" }, { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list, - cli_cmd_flag_none, + wpa_cli_complete_bss, cli_cmd_flag_none, "<addr> <home realm> = get HS20 nai home realm list" }, #endif /* CONFIG_HS20 */ - { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none, + { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL, + cli_cmd_flag_none, "<0/1> = disable/enable automatic reconnection" }, - { "tdls_discover", wpa_cli_cmd_tdls_discover, + { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL, cli_cmd_flag_none, "<addr> = request TDLS discovery with <addr>" }, - { "tdls_setup", wpa_cli_cmd_tdls_setup, + { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL, cli_cmd_flag_none, "<addr> = request TDLS setup with <addr>" }, - { "tdls_teardown", wpa_cli_cmd_tdls_teardown, + { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL, cli_cmd_flag_none, "<addr> = tear down TDLS with <addr>" }, - { "signal_poll", wpa_cli_cmd_signal_poll, + { "signal_poll", wpa_cli_cmd_signal_poll, NULL, cli_cmd_flag_none, "= get signal parameters" }, - { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, + { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, cli_cmd_flag_none, "= get TX/RX packet counters" }, - { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none, + { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL, + cli_cmd_flag_none, "= trigger IEEE 802.1X/EAPOL reauthentication" }, #ifdef CONFIG_AUTOSCAN - { "autoscan", wpa_cli_cmd_autoscan, cli_cmd_flag_none, + { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none, "[params] = Set or unset (if none) autoscan parameters" }, #endif /* CONFIG_AUTOSCAN */ + { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, + "<params..> = Sent unprocessed command" }, #ifdef ANDROID - { "driver", wpa_cli_cmd_driver, + { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none, "<command> = driver private commands" }, #endif - { NULL, NULL, cli_cmd_flag_none, NULL } + { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; @@ -3433,12 +2713,14 @@ static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad) } -static void print_help(void) +static void print_help(const char *cmd) { int n; printf("commands:\n"); - for (n = 0; wpa_cli_commands[n].cmd; n++) - print_cmd_help(&wpa_cli_commands[n], " "); + for (n = 0; wpa_cli_commands[n].cmd; n++) { + if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd)) + print_cmd_help(&wpa_cli_commands[n], " "); + } } @@ -3469,7 +2751,7 @@ static char ** wpa_list_cmd_list(void) int i, count; count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]); - res = os_zalloc(count * sizeof(char *)); + res = os_calloc(count, sizeof(char *)); if (res == NULL) return NULL; @@ -3488,19 +2770,11 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str, { int i; - if (os_strcasecmp(cmd, "bss") == 0) - return wpa_cli_complete_bss(str, pos); -#ifdef CONFIG_P2P - if (os_strcasecmp(cmd, "p2p_connect") == 0) - return wpa_cli_complete_p2p_connect(str, pos); - if (os_strcasecmp(cmd, "p2p_peer") == 0) - return wpa_cli_complete_p2p_peer(str, pos); - if (os_strcasecmp(cmd, "p2p_group_remove") == 0) - return wpa_cli_complete_p2p_group_remove(str, pos); -#endif /* CONFIG_P2P */ - for (i = 0; wpa_cli_commands[i].cmd; i++) { if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) { + if (wpa_cli_commands[i].completion) + return wpa_cli_commands[i].completion(str, + pos); edit_clear_line(); printf("\r%s\n", wpa_cli_commands[i].usage); edit_redraw(); @@ -3711,7 +2985,14 @@ static void wpa_cli_action_cb(char *msg, size_t len) static void wpa_cli_reconnect(void) { wpa_cli_close_connection(); - wpa_cli_open_connection(ctrl_ifname, 1); + if (wpa_cli_open_connection(ctrl_ifname, 1) < 0) + return; + + if (interactive) { + edit_clear_line(); + printf("\rConnection to wpa_supplicant re-established\n"); + edit_redraw(); + } } @@ -3783,6 +3064,33 @@ static void cli_event(const char *str) } +static int check_terminating(const char *msg) +{ + const char *pos = msg; + + if (*pos == '<') { + /* skip priority */ + pos = os_strchr(pos, '>'); + if (pos) + pos++; + else + pos = msg; + } + + if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) { + edit_clear_line(); + printf("\rConnection to wpa_supplicant lost - trying to " + "reconnect\n"); + edit_redraw(); + wpa_cli_attached = 0; + wpa_cli_close_connection(); + return 1; + } + + return 0; +} + + static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) { if (ctrl_conn == NULL) { @@ -3803,6 +3111,9 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) printf("\r%s\n", buf); edit_redraw(); } + + if (interactive && check_terminating(buf) > 0) + return; } } else { printf("Could not read pending message.\n"); @@ -3862,12 +3173,6 @@ static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx) } -static void wpa_cli_eloop_terminate(int sig, void *signal_ctx) -{ - eloop_terminate(); -} - - static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx) { wpa_cli_recv_pending(mon_conn, 0); @@ -3890,11 +3195,18 @@ static void wpa_cli_edit_eof_cb(void *ctx) } -static void wpa_cli_interactive(void) +static int warning_displayed = 0; +static char *hfile = NULL; +static int edit_started = 0; + +static void start_edit(void) { - char *home, *hfile = NULL; + char *home; + char *ps = NULL; - printf("\nInteractive mode\n\n"); +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + ps = wpa_ctrl_get_remote_ifname(ctrl_conn); +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ home = getenv("HOME"); if (home) { @@ -3905,17 +3217,52 @@ static void wpa_cli_interactive(void) os_snprintf(hfile, hfile_len, "%s/%s", home, fname); } - eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL); - edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb, - wpa_cli_edit_completion_cb, NULL, hfile); + if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb, + wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) { + eloop_terminate(); + return; + } + + edit_started = 1; eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL); +} + + +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 (!warning_displayed) { + printf("Could not connect to wpa_supplicant: " + "%s - re-trying\n", ctrl_ifname); + warning_displayed = 1; + } + eloop_register_timeout(1, 0, try_connection, NULL, NULL); + return; + } + + if (warning_displayed) + printf("Connection established.\n"); + start_edit(); +} + + +static void wpa_cli_interactive(void) +{ + printf("\nInteractive mode\n\n"); + + eloop_register_timeout(0, 0, try_connection, NULL, NULL); eloop_run(); + eloop_cancel_timeout(try_connection, NULL, NULL); cli_txt_list_flush(&p2p_peers); cli_txt_list_flush(&p2p_groups); cli_txt_list_flush(&bsses); - edit_deinit(hfile, wpa_cli_edit_filter_history_cb); + if (edit_started) + edit_deinit(hfile, wpa_cli_edit_filter_history_cb); os_free(hfile); eloop_cancel_timeout(wpa_cli_ping, NULL, NULL); wpa_cli_close_connection(); @@ -3974,10 +3321,10 @@ static void wpa_cli_cleanup(void) os_program_deinit(); } -static void wpa_cli_terminate(int sig) + +static void wpa_cli_terminate(int sig, void *ctx) { - wpa_cli_cleanup(); - exit(0); + eloop_terminate(); } @@ -4051,7 +3398,6 @@ static char * wpa_cli_get_default_ifname(void) int main(int argc, char *argv[]) { - int warning_displayed = 0; int c; int daemonize = 0; int ret = 0; @@ -4121,30 +3467,13 @@ int main(int argc, char *argv[]) } } -#ifndef _WIN32_WCE - signal(SIGINT, wpa_cli_terminate); - signal(SIGTERM, wpa_cli_terminate); -#endif /* _WIN32_WCE */ + eloop_register_signal_terminate(wpa_cli_terminate, NULL); if (ctrl_ifname == NULL) ctrl_ifname = wpa_cli_get_default_ifname(); if (interactive) { - for (; !global;) { - if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) { - if (warning_displayed) - printf("Connection established.\n"); - break; - } - - if (!warning_displayed) { - printf("Could not connect to wpa_supplicant: " - "%s - re-trying\n", ctrl_ifname); - warning_displayed = 1; - } - os_sleep(1, 0); - continue; - } + wpa_cli_interactive(); } else { if (!global && wpa_cli_open_connection(ctrl_ifname, 0) < 0) { @@ -4163,17 +3492,16 @@ int main(int argc, char *argv[]) return -1; } } - } - if (daemonize && os_daemonize(pid_file)) - return -1; + if (daemonize && os_daemonize(pid_file)) + return -1; - if (interactive) - wpa_cli_interactive(); - else if (action_file) - wpa_cli_action(ctrl_conn); - else - ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]); + if (action_file) + wpa_cli_action(ctrl_conn); + else + ret = wpa_request(ctrl_conn, argc - optind, + &argv[optind]); + } os_free(ctrl_ifname); eloop_destroy(); diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c index a9ec236..9b568f0 100644 --- a/wpa_supplicant/wpa_passphrase.c +++ b/wpa_supplicant/wpa_passphrase.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) return 1; } - pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32); + pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32); printf("network={\n"); printf("\tssid=\"%s\"\n", ssid); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 47abd9a..284a91d 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -21,6 +21,7 @@ #include "rsn_supp/wpa.h" #include "eloop.h" #include "config.h" +#include "utils/ext_password.h" #include "l2_packet/l2_packet.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -40,6 +41,7 @@ #include "gas_query.h" #include "ap.h" #include "p2p_supplicant.h" +#include "wifi_display.h" #include "notify.h" #include "bgscan.h" #include "autoscan.h" @@ -153,6 +155,11 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, keylen = 16; alg = WPA_ALG_CCMP; break; + case WPA_CIPHER_GCMP: + os_memcpy(key, ssid->psk, 16); + keylen = 16; + alg = WPA_ALG_GCMP; + break; case WPA_CIPHER_TKIP: /* WPA-None uses the same Michael MIC key for both TX and RX */ os_memcpy(key, ssid->psk, 16 + 8); @@ -191,6 +198,17 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) * So, wait a second until scanning again. */ wpa_supplicant_req_scan(wpa_s, 1, 0); + +#ifdef CONFIG_P2P + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after timed out authentication"); + } + } +#endif /* CONFIG_P2P */ } @@ -453,6 +471,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->bssid_filter = NULL; wnm_bss_keep_alive_deinit(wpa_s); + + ext_password_deinit(wpa_s->ext_pw); + wpa_s->ext_pw = NULL; + + wpabuf_free(wpa_s->last_gas_resp); } @@ -554,8 +577,16 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s) * optimization, so the initial connection is not * affected. */ - } else + } else { + struct wpa_scan_results *scan_res; wpa_s->bgscan_ssid = wpa_s->current_ssid; + scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, + 0); + if (scan_res) { + bgscan_notify_scan(wpa_s, scan_res); + wpa_scan_results_free(scan_res); + } + } } else wpa_s->bgscan_ssid = NULL; } @@ -631,6 +662,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, ssid ? ssid->id : -1, ssid && ssid->id_str ? ssid->id_str : ""); #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ + wpas_clear_temp_disabled(wpa_s, ssid, 1); wpa_s->new_connection = 0; wpa_s->reassociated_connection = 1; wpa_drv_set_operstate(wpa_s, 1); @@ -823,6 +855,8 @@ enum wpa_cipher cipher_suite2driver(int cipher) return CIPHER_WEP104; case WPA_CIPHER_CCMP: return CIPHER_CCMP; + case WPA_CIPHER_GCMP: + return CIPHER_GCMP; case WPA_CIPHER_TKIP: default: return CIPHER_TKIP; @@ -999,6 +1033,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, if (sel & WPA_CIPHER_CCMP) { wpa_s->group_cipher = WPA_CIPHER_CCMP; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP"); + } else if (sel & WPA_CIPHER_GCMP) { + wpa_s->group_cipher = WPA_CIPHER_GCMP; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP"); } else if (sel & WPA_CIPHER_TKIP) { wpa_s->group_cipher = WPA_CIPHER_TKIP; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP"); @@ -1018,6 +1055,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, if (sel & WPA_CIPHER_CCMP) { wpa_s->pairwise_cipher = WPA_CIPHER_CCMP; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP"); + } else if (sel & WPA_CIPHER_GCMP) { + wpa_s->pairwise_cipher = WPA_CIPHER_GCMP; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP"); } else if (sel & WPA_CIPHER_TKIP) { wpa_s->pairwise_cipher = WPA_CIPHER_TKIP; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP"); @@ -1099,13 +1139,70 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) { u8 psk[PMK_LEN]; - pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid, - bss->ssid_len, 4096, psk, PMK_LEN); + pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len, + 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); } #endif /* CONFIG_NO_PBKDF2 */ +#ifdef CONFIG_EXT_PASSWORD + if (ssid->ext_psk) { + struct wpabuf *pw = ext_password_get(wpa_s->ext_pw, + ssid->ext_psk); + char pw_str[64 + 1]; + u8 psk[PMK_LEN]; + + if (pw == NULL) { + wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK " + "found from external storage"); + return -1; + } + + if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) { + wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected " + "PSK length %d in external storage", + (int) wpabuf_len(pw)); + ext_password_free(pw); + return -1; + } + + os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw)); + pw_str[wpabuf_len(pw)] = '\0'; + +#ifndef CONFIG_NO_PBKDF2 + if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss) + { + pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len, + 4096, psk, PMK_LEN); + os_memset(pw_str, 0, sizeof(pw_str)); + wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " + "external passphrase)", + psk, PMK_LEN); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); + } else +#endif /* CONFIG_NO_PBKDF2 */ + if (wpabuf_len(pw) == 2 * PMK_LEN) { + if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) { + wpa_msg(wpa_s, MSG_INFO, "EXT PW: " + "Invalid PSK hex string"); + os_memset(pw_str, 0, sizeof(pw_str)); + ext_password_free(pw); + return -1; + } + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); + } else { + wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable " + "PSK available"); + os_memset(pw_str, 0, sizeof(pw_str)); + ext_password_free(pw); + return -1; + } + + os_memset(pw_str, 0, sizeof(pw_str)); + ext_password_free(pw); + } +#endif /* CONFIG_EXT_PASSWORD */ } else wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); @@ -1257,6 +1354,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, "key management and encryption suites"); return; } + } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss && + wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { + /* + * Both WPA and non-WPA IEEE 802.1X enabled in configuration - + * use non-WPA since the scan results did not indicate that the + * AP is using WPA or WPA2. + */ + wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); + wpa_ie_len = 0; + wpa_s->wpa_proto = 0; } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { wpa_ie_len = sizeof(wpa_ie); if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, @@ -1570,10 +1677,8 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s, struct wpa_ssid *old_ssid; wpa_clear_keys(wpa_s, addr); - wpa_supplicant_mark_disassoc(wpa_s); old_ssid = wpa_s->current_ssid; - wpa_s->current_ssid = NULL; - wpa_s->current_bss = NULL; + wpa_supplicant_mark_disassoc(wpa_s); wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); if (old_ssid != wpa_s->current_ssid) @@ -1662,6 +1767,8 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, was_disabled = other_ssid->disabled; other_ssid->disabled = 0; + if (was_disabled) + wpas_clear_temp_disabled(wpa_s, other_ssid, 0); if (was_disabled != other_ssid->disabled) wpas_notify_network_enabled_changed( @@ -1682,6 +1789,7 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, was_disabled = ssid->disabled; ssid->disabled = 0; + wpas_clear_temp_disabled(wpa_s, ssid, 1); if (was_disabled != ssid->disabled) wpas_notify_network_enabled_changed(wpa_s, ssid); @@ -1752,6 +1860,9 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, disconnected = 1; } + if (ssid) + wpas_clear_temp_disabled(wpa_s, ssid, 1); + /* * Mark all other networks disabled or mark all networks enabled if no * network specified. @@ -1763,6 +1874,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, continue; /* do not change persistent P2P group data */ other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0; + if (was_disabled && !other_ssid->disabled) + wpas_clear_temp_disabled(wpa_s, other_ssid, 0); if (was_disabled != other_ssid->disabled) wpas_notify_network_enabled_changed(wpa_s, other_ssid); @@ -2529,6 +2642,38 @@ static int pcsc_reader_init(struct wpa_supplicant *wpa_s) } +int wpas_init_ext_pw(struct wpa_supplicant *wpa_s) +{ + char *val, *pos; + + ext_password_deinit(wpa_s->ext_pw); + wpa_s->ext_pw = NULL; + eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL); + + if (!wpa_s->conf->ext_password_backend) + return 0; + + val = os_strdup(wpa_s->conf->ext_password_backend); + if (val == NULL) + return -1; + pos = os_strchr(val, ':'); + if (pos) + *pos++ = '\0'; + + wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val); + + wpa_s->ext_pw = ext_password_init(val, pos); + os_free(val); + if (wpa_s->ext_pw == NULL) { + wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend"); + return -1; + } + eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw); + + return 0; +} + + static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, struct wpa_interface *iface) { @@ -2754,6 +2899,9 @@ next_driver: if (pcsc_reader_init(wpa_s) < 0) return -1; + if (wpas_init_ext_pw(wpa_s) < 0) + return -1; + return 0; } @@ -3072,6 +3220,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) return NULL; } +#ifdef CONFIG_WIFI_DISPLAY + if (wifi_display_init(global) < 0) { + wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display"); + wpa_supplicant_deinit(global); + return NULL; + } +#endif /* CONFIG_WIFI_DISPLAY */ + return global; } @@ -3123,6 +3279,9 @@ void wpa_supplicant_deinit(struct wpa_global *global) if (global == NULL) return; +#ifdef CONFIG_WIFI_DISPLAY + wifi_display_deinit(global); +#endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_P2P wpas_p2p_deinit_global(global); #endif /* CONFIG_P2P */ @@ -3182,6 +3341,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); + #ifdef CONFIG_WPS wpas_wps_update_config(wpa_s); #endif /* CONFIG_WPS */ @@ -3304,6 +3466,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) */ wpa_supplicant_req_scan(wpa_s, timeout / 1000, 1000 * (timeout % 1000)); + +#ifdef CONFIG_P2P + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after failed association"); + } + } +#endif /* CONFIG_P2P */ } @@ -3417,6 +3590,10 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) return 1; /* invalid WEP key */ } + if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && + !ssid->ext_psk) + return 1; + return 0; } @@ -3429,3 +3606,63 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s) return 0; return -1; } + + +void wpas_auth_failed(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + int dur; + struct os_time now; + + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "Authentication failure but no known " + "SSID block"); + return; + } + + if (ssid->key_mgmt == WPA_KEY_MGMT_WPS) + return; + + ssid->auth_failures++; + if (ssid->auth_failures > 50) + dur = 300; + else if (ssid->auth_failures > 20) + dur = 120; + else if (ssid->auth_failures > 10) + dur = 60; + else if (ssid->auth_failures > 5) + dur = 30; + else if (ssid->auth_failures > 1) + dur = 20; + else + dur = 10; + + os_get_time(&now); + if (now.sec + dur <= ssid->disabled_until.sec) + return; + + ssid->disabled_until.sec = now.sec + dur; + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED + "id=%d ssid=\"%s\" auth_failures=%u duration=%d", + ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len), + ssid->auth_failures, dur); +} + + +void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, int clear_failures) +{ + if (ssid == NULL) + return; + + if (ssid->disabled_until.sec) { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED + "id=%d ssid=\"%s\"", + ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + } + ssid->disabled_until.sec = 0; + ssid->disabled_until.usec = 0; + if (clear_failures) + ssid->auth_failures = 0; +} diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 3ebbcc2..2c07fd0 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -241,20 +241,30 @@ fast_reauth=1 # This is an optional set of parameters for automatic scanning # within an interface in following format: #autoscan=<autoscan module name>:<module parameters> -# autoscan is like bgscan but on disconnected or inactive state. -# For instance, on exponential module parameters would be <base>:<limit> +#Â autoscan is like bgscan but on disconnected or inactive state. +#Â For instance, on exponential module parameters would be <base>:<limit> #autoscan=exponential:3:300 # Which means a delay between scans on a base exponential of 3, -# up to the limit of 300 seconds (3, 9, 27 ... 300) -# For periodic module, parameters would be <fixed interval> +#Â 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 # filter_ssids - SSID-based scan result filtering # 0 = do not filter scan results (default) # 1 = only include configured SSIDs in scan results/BSS table #filter_ssids=0 +# Password (and passphrase, etc.) backend for external storage +# format: <backend name>[:<optional backend parameters>] +#ext_password_backend=test:pw1=password|pw2=testing + +# Timeout in seconds to detect STA inactivity (default: 300 seconds) +# +# This timeout value is used in P2P GO mode to clean up +# inactive stations. +#p2p_go_max_inactivity=300 + # Interworking (IEEE 802.11u) @@ -267,6 +277,14 @@ fast_reauth=1 # is enabled. # hessid=00:11:22:33:44:55 +# Automatic network selection behavior +# 0 = do not automatically go through Interworking network selection +# (i.e., require explicit interworking_select command for this; default) +# 1 = perform Interworking network selection if one or more +# credentials have been configured and scan did not find a +# matching network block +#auto_interworking=0 + # credential block # # Each credential used for automatic network selection is configured as a set @@ -336,6 +354,26 @@ fast_reauth=1 # This is used to compare against the Domain Name List to figure out # whether the AP is operated by the Home SP. # +# roaming_consortium: Roaming Consortium OI +# If roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that can be used to determine which access +# points support authentication with this credential. This is an +# alternative to the use of the realm parameter. When using Roaming +# Consortium to match the network, the EAP parameters need to be +# pre-configured with the credential since the NAI Realm information +# may not be available or fetched. +# +# eap: Pre-configured EAP method +# This optional field can be used to specify which EAP method will be +# used with this credential. If not set, the EAP method is selected +# automatically based on ANQP information (e.g., NAI Realm). +# +# phase1: Pre-configure Phase 1 (outer authentication) parameters +# This optional field is used with like the 'eap' parameter. +# +# phase2: Pre-configure Phase 2 (inner authentication) parameters +# This optional field is used with like the 'eap' parameter. +# # for example: # #cred={ @@ -350,6 +388,17 @@ fast_reauth=1 # imsi="310026-000000000" # milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82" #} +# +#cred={ +# realm="example.com" +# username="user" +# password="password" +# ca_cert="/etc/wpa_supplicant/ca.pem" +# domain="example.com" +# roaming_consortium=223344 +# eap=TTLS +# phase2="auth=MSCHAPV2" +#} # Hotspot 2.0 # hs20=1 @@ -371,8 +420,10 @@ fast_reauth=1 # to external action script through wpa_cli as WPA_ID_STR environment # variable to make it easier to do network specific configuration. # -# ssid: SSID (mandatory); either as an ASCII string with double quotation or -# as hex string; network name +# ssid: SSID (mandatory); network name in one of the optional formats: +# - an ASCII string with double quotation +# - a hex string (two characters per octet of SSID) +# - a printf-escaped ASCII string P"<escaped string>" # # scan_ssid: # 0 = do not scan this SSID with specific Probe Request frames (default) @@ -473,7 +524,8 @@ fast_reauth=1 # The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e., # 32 bytes or as an ASCII passphrase (in which case, the real PSK will be # generated using the passphrase and SSID). ASCII passphrase must be between -# 8 and 63 characters (inclusive). +# 8 and 63 characters (inclusive). ext:<name of external PSK field> format can +# be used to indicate that the PSK/passphrase is stored in external storage. # This field is not needed, if WPA-EAP is used. # Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys # from ASCII passphrase. This process uses lot of CPU and wpa_supplicant @@ -542,7 +594,8 @@ fast_reauth=1 # MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). # EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit # PSK) is also configured using this field. For EAP-GPSK, this is a -# variable length PSK. +# variable length PSK. ext:<name of external password field> format can +# be used to indicate that the password is stored in external storage. # ca_cert: File path to CA certificate file (PEM/DER). This file can have one # or more trusted CA certificates. If ca_cert and ca_path are not # included, server certificate will not be verified. This is insecure and @@ -645,6 +698,25 @@ fast_reauth=1 # phase2: Phase2 (inner authentication with TLS tunnel) parameters # (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or # "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS) +# +# TLS-based methods can use the following parameters to control TLS behavior +# (these are normally in the phase1 parameter, but can be used also in the +# phase2 parameter when EAP-TLS is used within the inner tunnel): +# tls_allow_md5=1 - allow MD5-based certificate signatures (depending on the +# TLS library, these may be disabled by default to enforce stronger +# security) +# tls_disable_time_checks=1 - ignore certificate validity time (this requests +# the TLS library to accept certificates even if they are not currently +# valid, i.e., have expired or have not yet become valid; this should be +# used only for testing purposes) +# tls_disable_session_ticket=1 - disable TLS Session Ticket extension +# tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used +# Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS +# as a workaround for broken authentication server implementations unless +# EAP workarounds are disabled with eap_workarounds=0. +# For EAP-FAST, this must be set to 0 (or left unconfigured for the +# default value to be used automatically). +# # Following certificate/private key fields are used in inner Phase2 # authentication when using EAP-TTLS or EAP-PEAP. # ca_cert2: File path to CA certificate file. This file can have one or more diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 3f6669d..523b50d 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal definitions - * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -239,6 +239,12 @@ struct wpa_global { WPA_CONC_PREF_STA, WPA_CONC_PREF_P2P } conc_pref; + +#ifdef CONFIG_WIFI_DISPLAY + int wifi_display; +#define MAX_WFD_SUBELEMS 10 + struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS]; +#endif /* CONFIG_WIFI_DISPLAY */ }; @@ -249,6 +255,17 @@ enum offchannel_send_action_result { OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */ }; +struct wps_ap_info { + u8 bssid[ETH_ALEN]; + enum wps_ap_info_type { + WPS_AP_NOT_SEL_REG, + WPS_AP_SEL_REG, + WPS_AP_SEL_REG_OUR + } type; + unsigned int tries; + struct os_time last_attempt; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -514,23 +531,14 @@ struct wpa_supplicant { */ char cross_connect_uplink[100]; - enum { - P2P_GROUP_REMOVAL_UNKNOWN, - P2P_GROUP_REMOVAL_REQUESTED, - P2P_GROUP_REMOVAL_IDLE_TIMEOUT, - P2P_GROUP_REMOVAL_UNAVAILABLE, - P2P_GROUP_REMOVAL_GO_ENDING_SESSION, -#ifdef ANDROID_P2P - P2P_GROUP_REMOVAL_FREQ_CONFLICT -#endif - } removal_reason; - unsigned int p2p_cb_on_scan_complete:1; + unsigned int sta_scan_pending:1; unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1; unsigned int p2p_fallback_to_go_neg:1; unsigned int p2p_pd_before_go_neg:1; + unsigned int p2p_go_ht40:1; int p2p_persistent_id; int p2p_go_intent; int p2p_connect_freq; @@ -547,6 +555,10 @@ struct wpa_supplicant { struct wpa_ssid *connect_without_scan; + struct wps_ap_info *wps_ap; + size_t num_wps_ap; + int wps_ap_iter; + int after_wps; int known_wps_freq; unsigned int wps_freq; @@ -564,6 +576,7 @@ struct wpa_supplicant { unsigned int fetch_anqp_in_progress:1; unsigned int network_select:1; unsigned int auto_select:1; + unsigned int auto_network_select:1; #endif /* CONFIG_INTERWORKING */ unsigned int drv_capa_known; @@ -577,6 +590,12 @@ struct wpa_supplicant { /* WLAN_REASON_* reason codes. Negative if locally generated. */ int disconnect_reason; + + struct ext_password_data *ext_pw; + + struct wpabuf *last_gas_resp; + u8 last_gas_addr[ETH_ALEN]; + u8 last_gas_dialog_token; }; @@ -659,6 +678,9 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s); int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); +void wpas_auth_failed(struct wpa_supplicant *wpa_s); +void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, int clear_failures); void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s); /** @@ -700,4 +722,6 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid) int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +int wpas_init_ext_pw(struct wpa_supplicant *wpa_s); + #endif /* WPA_SUPPLICANT_I_H */ diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 0873b1a..23966b8 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -43,6 +43,15 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_clear_wps(struct wpa_supplicant *wpa_s); +static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s) +{ + os_free(wpa_s->wps_ap); + wpa_s->wps_ap = NULL; + wpa_s->num_wps_ap = 0; + wpa_s->wps_ap_iter = 0; +} + + int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { if (!wpa_s->wps_success && @@ -66,6 +75,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) return 1; } + wpas_wps_clear_ap_info(wpa_s); eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success) wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL); @@ -263,9 +273,13 @@ static int wpa_supplicant_wps_cred(void *ctx, ssid->eap.phase1 = NULL; os_free(ssid->eap.eap_methods); ssid->eap.eap_methods = NULL; - if (!ssid->p2p_group) + if (!ssid->p2p_group) { ssid->temporary = 0; - ssid->bssid_set = 0; + ssid->bssid_set = 0; + } + ssid->disabled_until.sec = 0; + ssid->disabled_until.usec = 0; + ssid->auth_failures = 0; } else { wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the " "received credential"); @@ -353,16 +367,6 @@ static int wpa_supplicant_wps_cred(void *ctx, ssid->key_mgmt = WPA_KEY_MGMT_PSK; ssid->proto = WPA_PROTO_WPA; break; - case WPS_AUTH_WPA: - ssid->auth_alg = WPA_AUTH_ALG_OPEN; - ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X; - ssid->proto = WPA_PROTO_WPA; - break; - case WPS_AUTH_WPA2: - ssid->auth_alg = WPA_AUTH_ALG_OPEN; - ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X; - ssid->proto = WPA_PROTO_RSN; - break; case WPS_AUTH_WPA2PSK: ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_PSK; @@ -712,6 +716,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s) wpa_config_remove_network(wpa_s->conf, id); } } + + wpas_wps_clear_ap_info(wpa_s); } @@ -907,6 +913,7 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); + wpa_s->wps_ap_iter = 1; wpas_wps_reassoc(wpa_s, ssid, bssid); return rpin; } @@ -933,7 +940,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); wpas_clear_wps(wpa_s); - } + } else + wpas_wps_clear_ap_info(wpa_s); return 0; } @@ -1239,6 +1247,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s) void wpas_wps_deinit(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); + wpas_wps_clear_ap_info(wpa_s); if (wpa_s->wps == NULL) return; @@ -1920,3 +1929,130 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_WPS_NFC */ + + +extern int wpa_debug_level; + +static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) +{ + size_t i; + struct os_time now; + + if (wpa_debug_level > MSG_DEBUG) + return; + + if (wpa_s->wps_ap == NULL) + return; + + os_get_time(&now); + + for (i = 0; i < wpa_s->num_wps_ap; i++) { + struct wps_ap_info *ap = &wpa_s->wps_ap[i]; + struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid); + + wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d " + "tries=%d last_attempt=%d sec ago blacklist=%d", + (int) i, MAC2STR(ap->bssid), ap->type, ap->tries, + ap->last_attempt.sec > 0 ? + (int) now.sec - (int) ap->last_attempt.sec : -1, + e ? e->count : 0); + } +} + + +static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + size_t i; + + if (wpa_s->wps_ap == NULL) + return NULL; + + for (i = 0; i < wpa_s->num_wps_ap; i++) { + struct wps_ap_info *ap = &wpa_s->wps_ap[i]; + if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0) + return ap; + } + + return NULL; +} + + +static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) +{ + struct wpabuf *wps; + enum wps_ap_info_type type; + struct wps_ap_info *ap; + int r; + + if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL) + return; + + wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); + if (wps == NULL) + return; + + r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1); + if (r == 2) + type = WPS_AP_SEL_REG_OUR; + else if (r == 1) + type = WPS_AP_SEL_REG; + else + type = WPS_AP_NOT_SEL_REG; + + wpabuf_free(wps); + + ap = wpas_wps_get_ap_info(wpa_s, res->bssid); + if (ap) { + if (ap->type != type) { + wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR + " changed type %d -> %d", + MAC2STR(res->bssid), ap->type, type); + ap->type = type; + if (type != WPS_AP_NOT_SEL_REG) + wpa_blacklist_del(wpa_s, ap->bssid); + } + return; + } + + ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1, + sizeof(struct wps_ap_info)); + if (ap == NULL) + return; + + wpa_s->wps_ap = ap; + ap = &wpa_s->wps_ap[wpa_s->num_wps_ap]; + wpa_s->num_wps_ap++; + + os_memset(ap, 0, sizeof(*ap)); + os_memcpy(ap->bssid, res->bssid, ETH_ALEN); + ap->type = type; + wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added", + MAC2STR(ap->bssid), ap->type); +} + + +void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + size_t i; + + for (i = 0; i < scan_res->num; i++) + wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]); + + wpas_wps_dump_ap_info(wpa_s); +} + + +void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wps_ap_info *ap; + if (!wpa_s->wps_ap_iter) + return; + ap = wpas_wps_get_ap_info(wpa_s, bssid); + if (ap == NULL) + return; + ap->tries++; + os_get_time(&ap->last_attempt); +} diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 5a49a8f..36f1e02 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -10,6 +10,7 @@ #define WPS_SUPPLICANT_H struct wpa_scan_res; +struct wpa_scan_results; #ifdef CONFIG_WPS @@ -68,6 +69,9 @@ struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef); int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid); int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, const struct wpabuf *data); +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); #else /* CONFIG_WPS */ @@ -120,6 +124,16 @@ static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s) return 0; } +static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ +} + +static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ +} + #endif /* CONFIG_WPS */ #endif /* WPS_SUPPLICANT_H */ |