summaryrefslogtreecommitdiff
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorAndrew Shadura <andrewsh@debian.org>2016-10-20 18:23:40 +0200
committerAndrew Shadura <andrewsh@debian.org>2016-10-20 18:23:40 +0200
commit1e2b7568b4f69a9da79de660a1a04ef077479628 (patch)
tree252210229f2c2d4387457403887894a73eff4cf6 /wpa_supplicant
parentaa5e2237f3bbd73853b3ffbb4bf693298c409792 (diff)
Imported Upstream version 2.6
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/Android.mk166
-rw-r--r--wpa_supplicant/ChangeLog144
-rw-r--r--wpa_supplicant/Makefile162
-rw-r--r--wpa_supplicant/README48
-rw-r--r--wpa_supplicant/README-HS2067
-rw-r--r--wpa_supplicant/README-P2P22
-rw-r--r--wpa_supplicant/android.config12
-rw-r--r--wpa_supplicant/ap.c200
-rw-r--r--wpa_supplicant/ap.h10
-rw-r--r--wpa_supplicant/autoscan.c34
-rw-r--r--wpa_supplicant/autoscan.h10
-rw-r--r--wpa_supplicant/bgscan.c6
-rw-r--r--wpa_supplicant/bgscan.h9
-rw-r--r--wpa_supplicant/binder/.clang-format9
-rw-r--r--wpa_supplicant/binder/binder.cpp104
-rw-r--r--wpa_supplicant/binder/binder.h46
-rw-r--r--wpa_supplicant/binder/binder_constants.cpp18
-rw-r--r--wpa_supplicant/binder/binder_constants.h21
-rw-r--r--wpa_supplicant/binder/binder_i.h28
-rw-r--r--wpa_supplicant/binder/binder_manager.cpp100
-rw-r--r--wpa_supplicant/binder/binder_manager.h58
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl16
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl59
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl20
-rw-r--r--wpa_supplicant/binder/iface.cpp16
-rw-r--r--wpa_supplicant/binder/iface.h42
-rw-r--r--wpa_supplicant/binder/supplicant.cpp127
-rw-r--r--wpa_supplicant/binder/supplicant.h55
-rw-r--r--wpa_supplicant/bss.c97
-rw-r--r--wpa_supplicant/bss.h20
-rw-r--r--wpa_supplicant/config.c190
-rw-r--r--wpa_supplicant/config.h88
-rw-r--r--wpa_supplicant/config_file.c45
-rw-r--r--wpa_supplicant/config_ssid.h45
-rw-r--r--wpa_supplicant/config_winreg.c1
-rw-r--r--wpa_supplicant/ctrl_iface.c1052
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c170
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c358
-rw-r--r--wpa_supplicant/dbus/dbus-wpa_supplicant.conf2
-rw-r--r--wpa_supplicant/dbus/dbus_common_i.h10
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.c74
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.h15
-rw-r--r--wpa_supplicant/dbus/dbus_new.c359
-rw-r--r--wpa_supplicant/dbus/dbus_new.h7
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c655
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h267
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c201
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h164
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_wps.c26
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.c9
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.h12
-rw-r--r--wpa_supplicant/dbus/dbus_new_introspect.c4
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.c23
-rw-r--r--wpa_supplicant/defconfig44
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml9
-rw-r--r--wpa_supplicant/driver_i.h82
-rw-r--r--wpa_supplicant/eapol_test.c18
-rw-r--r--wpa_supplicant/events.c530
-rw-r--r--wpa_supplicant/gas_query.c154
-rw-r--r--wpa_supplicant/gas_query.h2
-rw-r--r--wpa_supplicant/hs20_supplicant.c313
-rw-r--r--wpa_supplicant/hs20_supplicant.h15
-rw-r--r--wpa_supplicant/ibss_rsn.c12
-rw-r--r--wpa_supplicant/ibss_rsn.h3
-rw-r--r--wpa_supplicant/interworking.c231
-rw-r--r--wpa_supplicant/interworking.h3
-rw-r--r--wpa_supplicant/libwpa_test.c32
-rw-r--r--wpa_supplicant/main.c96
-rw-r--r--wpa_supplicant/mbo.c836
-rw-r--r--wpa_supplicant/mesh.c130
-rw-r--r--wpa_supplicant/mesh.h3
-rw-r--r--wpa_supplicant/mesh_mpm.c376
-rw-r--r--wpa_supplicant/mesh_mpm.h5
-rw-r--r--wpa_supplicant/mesh_rsn.c374
-rw-r--r--wpa_supplicant/mesh_rsn.h11
-rw-r--r--wpa_supplicant/notify.c25
-rw-r--r--wpa_supplicant/notify.h3
-rw-r--r--wpa_supplicant/offchannel.c52
-rw-r--r--wpa_supplicant/p2p_supplicant.c1289
-rw-r--r--wpa_supplicant/p2p_supplicant.h26
-rw-r--r--wpa_supplicant/p2p_supplicant_sd.c18
-rw-r--r--wpa_supplicant/scan.c471
-rw-r--r--wpa_supplicant/scan.h13
-rw-r--r--wpa_supplicant/sme.c125
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant.service.in4
-rw-r--r--wpa_supplicant/tests/link_test.c83
-rw-r--r--wpa_supplicant/tests/test_eap_sim_common.c47
-rw-r--r--wpa_supplicant/tests/test_wpa.c369
-rw-r--r--wpa_supplicant/wmm_ac.h2
-rw-r--r--wpa_supplicant/wnm_sta.c503
-rw-r--r--wpa_supplicant/wnm_sta.h2
-rw-r--r--wpa_supplicant/wpa_cli.c529
-rw-r--r--wpa_supplicant/wpa_priv.c61
-rw-r--r--wpa_supplicant/wpa_supplicant.c1197
-rw-r--r--wpa_supplicant/wpa_supplicant.conf184
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h149
-rw-r--r--wpa_supplicant/wpas_glue.c11
-rw-r--r--wpa_supplicant/wpas_kay.c11
-rw-r--r--wpa_supplicant/wpas_module_tests.c33
-rw-r--r--wpa_supplicant/wps_supplicant.c46
-rw-r--r--wpa_supplicant/wps_supplicant.h7
107 files changed, 10586 insertions, 3468 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 0d818ed..a8d6a7f 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -49,6 +49,12 @@ ifeq ($(TARGET_ARCH),arm)
L_CFLAGS += -mabi=aapcs-linux
endif
+# C++ flags for binder interface
+L_CPPFLAGS := -std=c++11 -Wall -Werror
+# TODO: Remove these allowed warnings later.
+L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter
+L_CPPFLAGS += -Wno-unused-private-field
+
INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/src
INCLUDES += $(LOCAL_PATH)/src/common
@@ -65,7 +71,6 @@ INCLUDES += $(LOCAL_PATH)/src/rsn_supp
INCLUDES += $(LOCAL_PATH)/src/tls
INCLUDES += $(LOCAL_PATH)/src/utils
INCLUDES += $(LOCAL_PATH)/src/wps
-INCLUDES += external/openssl/include
INCLUDES += system/security/keystore/include
ifdef CONFIG_DRIVER_NL80211
ifneq ($(wildcard external/libnl),)
@@ -95,6 +100,7 @@ OBJS_p += src/utils/wpabuf.c
OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
OBJS_c += src/utils/wpa_debug.c
OBJS_c += src/utils/common.c
+OBJS_c += src/common/cli.c
OBJS_d =
OBJS_priv =
@@ -270,6 +276,7 @@ endif
ifdef CONFIG_IBSS_RSN
NEED_RSN_AUTHENTICATOR=y
L_CFLAGS += -DCONFIG_IBSS_RSN
+L_CFLAGS += -DCONFIG_NO_VLAN
OBJS += ibss_rsn.c
endif
@@ -386,7 +393,6 @@ EAPDYN += src/eap_peer/eap_tls.so
else
L_CFLAGS += -DEAP_TLS
OBJS += src/eap_peer/eap_tls.c
-OBJS_h += src/eap_server/eap_server_tls.c
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -397,7 +403,6 @@ ifdef CONFIG_EAP_UNAUTH_TLS
L_CFLAGS += -DEAP_UNAUTH_TLS
ifndef CONFIG_EAP_TLS
OBJS += src/eap_peer/eap_tls.c
-OBJS_h += src/eap_server/eap_server_tls.c
TLS_FUNCS=y
endif
CONFIG_IEEE8021X_EAPOL=y
@@ -412,7 +417,6 @@ else
L_CFLAGS += -DEAP_PEAP
OBJS += src/eap_peer/eap_peap.c
OBJS += src/eap_common/eap_peap_common.c
-OBJS_h += src/eap_server/eap_server_peap.c
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -426,7 +430,6 @@ EAPDYN += src/eap_peer/eap_ttls.so
else
L_CFLAGS += -DEAP_TTLS
OBJS += src/eap_peer/eap_ttls.c
-OBJS_h += src/eap_server/eap_server_ttls.c
endif
TLS_FUNCS=y
ifndef CONFIG_FIPS
@@ -444,7 +447,6 @@ EAPDYN += src/eap_peer/eap_md5.so
else
L_CFLAGS += -DEAP_MD5
OBJS += src/eap_peer/eap_md5.c
-OBJS_h += src/eap_server/eap_server_md5.c
endif
CHAP=y
CONFIG_IEEE8021X_EAPOL=y
@@ -467,7 +469,6 @@ else
L_CFLAGS += -DEAP_MSCHAPv2
OBJS += src/eap_peer/eap_mschapv2.c
OBJS += src/eap_peer/mschapv2.c
-OBJS_h += src/eap_server/eap_server_mschapv2.c
endif
MS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -481,7 +482,6 @@ EAPDYN += src/eap_peer/eap_gtc.so
else
L_CFLAGS += -DEAP_GTC
OBJS += src/eap_peer/eap_gtc.c
-OBJS_h += src/eap_server/eap_server_gtc.c
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -506,7 +506,6 @@ EAPDYN += src/eap_peer/eap_sim.so
else
L_CFLAGS += -DEAP_SIM
OBJS += src/eap_peer/eap_sim.c
-OBJS_h += src/eap_server/eap_server_sim.c
endif
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_SIM_COMMON=y
@@ -534,7 +533,6 @@ EAPDYN += src/eap_peer/eap_psk.so
else
L_CFLAGS += -DEAP_PSK
OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c
-OBJS_h += src/eap_server/eap_server_psk.c
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
@@ -551,7 +549,6 @@ EAPDYN += src/eap_peer/eap_aka.so
else
L_CFLAGS += -DEAP_AKA
OBJS += src/eap_peer/eap_aka.c
-OBJS_h += src/eap_server/eap_server_aka.c
endif
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_SIM_COMMON=y
@@ -577,7 +574,6 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += src/eap_common/eap_sim_common.c
-OBJS_h += src/eap_server/eap_sim_db.c
NEED_AES=y
NEED_FIPS186_2_PRF=y
endif
@@ -592,7 +588,6 @@ else
L_CFLAGS += -DEAP_FAST
OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c
OBJS += src/eap_common/eap_fast_common.c
-OBJS_h += src/eap_server/eap_server_fast.c
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -607,7 +602,6 @@ EAPDYN += src/eap_peer/eap_pax.so
else
L_CFLAGS += -DEAP_PAX
OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c
-OBJS_h += src/eap_server/eap_server_pax.c
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -620,7 +614,6 @@ EAPDYN += src/eap_peer/eap_sake.so
else
L_CFLAGS += -DEAP_SAKE
OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c
-OBJS_h += src/eap_server/eap_server_sake.c
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -633,7 +626,6 @@ EAPDYN += src/eap_peer/eap_gpsk.so
else
L_CFLAGS += -DEAP_GPSK
OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c
-OBJS_h += src/eap_server/eap_server_gpsk.c
endif
CONFIG_IEEE8021X_EAPOL=y
ifdef CONFIG_EAP_GPSK_SHA256
@@ -646,7 +638,6 @@ endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_PWD
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
-OBJS_h += src/eap_server/eap_server_pwd.c
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
endif
@@ -659,7 +650,6 @@ EAPDYN += src/eap_peer/eap_eke.so
else
L_CFLAGS += -DEAP_EKE
OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c
-OBJS_h += src/eap_server/eap_server_eke.c
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
@@ -682,7 +672,6 @@ OBJS += src/wps/wps_attr_process.c
OBJS += src/wps/wps_dev_attr.c
OBJS += src/wps/wps_enrollee.c
OBJS += src/wps/wps_registrar.c
-OBJS_h += src/eap_server/eap_server_wsc.c
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_SHA256=y
@@ -745,8 +734,6 @@ else
L_CFLAGS += -DEAP_IKEV2
OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c
OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
-OBJS_h += src/eap_server/eap_server_ikev2.c
-OBJS_h += src/eap_server/ikev2.c
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
@@ -762,7 +749,6 @@ EAPDYN += src/eap_peer/eap_vendor_test.so
else
L_CFLAGS += -DEAP_VENDOR_TEST
OBJS += src/eap_peer/eap_vendor_test.c
-OBJS_h += src/eap_server/eap_server_vendor_test.c
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -772,8 +758,6 @@ ifdef CONFIG_EAP_TNC
L_CFLAGS += -DEAP_TNC
OBJS += src/eap_peer/eap_tnc.c
OBJS += src/eap_peer/tncc.c
-OBJS_h += src/eap_server/eap_server_tnc.c
-OBJS_h += src/eap_server/tncs.c
NEED_BASE64=y
ifndef CONFIG_NATIVE_WINDOWS
ifndef CONFIG_DRIVER_BSD
@@ -820,6 +804,8 @@ OBJS += src/ap/ap_drv_ops.c
OBJS += src/ap/beacon.c
OBJS += src/ap/bss_load.c
OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/neighbor_db.c
+OBJS += src/ap/rrm.c
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
ifdef CONFIG_IEEE80211AC
@@ -829,6 +815,9 @@ endif
ifdef CONFIG_WNM
OBJS += src/ap/wnm_ap.c
endif
+ifdef CONFIG_MBO
+OBJS += src/ap/mbo_ap.c
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += src/ap/ctrl_iface_ap.c
endif
@@ -845,6 +834,11 @@ L_CFLAGS += -DCONFIG_IEEE80211AC
endif
endif
+ifdef CONFIG_MBO
+OBJS += mbo.c
+L_CFLAGS += -DCONFIG_MBO
+endif
+
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
@@ -880,34 +874,10 @@ OBJS += src/ap/peerkey_auth.c
endif
endif
-ifdef CONFIG_EAP_SERVER
-L_CFLAGS += -DEAP_SERVER
-OBJS_h += src/eap_server/eap_server.c
-OBJS_h += src/eap_server/eap_server_identity.c
-OBJS_h += src/eap_server/eap_server_methods.c
-endif
-
-ifdef CONFIG_RADIUS_CLIENT
-OBJS_h += src/utils/ip_addr.c
-OBJS_h += src/radius/radius.c
-OBJS_h += src/radius/radius_client.c
-endif
-
-ifdef CONFIG_AUTHENTICATOR
-OBJS_h += src/eapol_auth/eapol_auth_sm.c
-OBJS_h += src/ap/ieee802_1x.c
-endif
-
-ifdef CONFIG_WPA_AUTHENTICATOR
-OBJS_h += src/ap/wpa_auth.c
-OBJS_h += src/ap/wpa_auth_ie.c
-OBJS_h += src/ap/pmksa_cache_auth.c
-ifdef CONFIG_IEEE80211R
-OBJS_h += src/ap/wpa_auth_ft.c
-endif
-ifdef CONFIG_PEERKEY
-OBJS_h += src/ap/peerkey_auth.c
-endif
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
endif
ifdef CONFIG_PCSC
@@ -961,7 +931,6 @@ ifdef TLS_FUNCS
NEED_DES=y
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += src/eap_peer/eap_tls_common.c
-OBJS_h += src/eap_server/eap_server_tls_common.c
ifndef CONFIG_FIPS
NEED_TLS_PRF=y
NEED_SHA1=y
@@ -986,6 +955,7 @@ ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
L_CFLAGS += -DEAP_TLS_OPENSSL
OBJS += src/crypto/tls_openssl.c
+OBJS += src/crypto/tls_openssl_ocsp.c
LIBS += -lssl
endif
OBJS += src/crypto/crypto_openssl.c
@@ -1034,6 +1004,7 @@ OBJS += src/tls/tlsv1_cred.c
OBJS += src/tls/tlsv1_client.c
OBJS += src/tls/tlsv1_client_write.c
OBJS += src/tls/tlsv1_client_read.c
+OBJS += src/tls/tlsv1_client_ocsp.c
OBJS += src/tls/asn1.c
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
@@ -1087,6 +1058,8 @@ CONFIG_INTERNAL_SHA1=y
CONFIG_INTERNAL_MD4=y
CONFIG_INTERNAL_MD5=y
CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
@@ -1273,10 +1246,19 @@ SHA256OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += src/crypto/sha256-internal.c
endif
+ifdef CONFIG_INTERNAL_SHA384
+L_CFLAGS += -DCONFIG_INTERNAL_SHA384
+SHA256OBJS += src/crypto/sha384-internal.c
+endif
+ifdef CONFIG_INTERNAL_SHA512
+L_CFLAGS += -DCONFIG_INTERNAL_SHA512
+SHA256OBJS += src/crypto/sha512-internal.c
+endif
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += src/crypto/sha256-tlsprf.c
endif
ifdef NEED_HMAC_SHA256_KDF
+L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
SHA256OBJS += src/crypto/sha256-kdf.c
endif
OBJS += $(SHA256OBJS)
@@ -1319,6 +1301,7 @@ endif
L_CFLAGS += -DCONFIG_CTRL_IFACE
ifeq ($(CONFIG_CTRL_IFACE), unix)
L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+OBJS += src/common/ctrl_iface_common.c
endif
ifeq ($(CONFIG_CTRL_IFACE), udp)
L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
@@ -1342,12 +1325,6 @@ ifdef CONFIG_WPS
DBUS_OBJS += dbus/dbus_old_handlers_wps.c
endif
DBUS_OBJS += dbus/dbus_dict_helpers.c
-ifndef DBUS_LIBS
-DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
-endif
-ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
-endif
DBUS_CFLAGS += $(DBUS_INCLUDE)
endif
@@ -1363,12 +1340,6 @@ endif
ifdef CONFIG_P2P
DBUS_OBJS += dbus/dbus_new_handlers_p2p.c
endif
-ifndef DBUS_LIBS
-DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
-endif
-ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
-endif
ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
DBUS_OBJS += dbus/dbus_new_introspect.c
DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
@@ -1383,7 +1354,11 @@ endif
OBJS += $(DBUS_OBJS)
L_CFLAGS += $(DBUS_CFLAGS)
-LIBS += $(DBUS_LIBS)
+
+ifdef CONFIG_CTRL_IFACE_BINDER
+WPA_SUPPLICANT_USE_BINDER=y
+L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
+endif
ifdef CONFIG_READLINE
OBJS_c += src/utils/edit_readline.c
@@ -1529,12 +1504,6 @@ endif
OBJS += src/drivers/driver_common.c
-OBJS_wpa_rm := ctrl_iface.c ctrl_iface_unix.c
-OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.c
-ifdef CONFIG_AUTHENTICATOR
-OBJS_wpa += tests/link_test.c
-endif
-OBJS_wpa += $(OBJS_l2)
OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
@@ -1608,6 +1577,13 @@ endif
ifeq ($(CONFIG_TLS), openssl)
LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
endif
+
+# With BoringSSL we need libkeystore-engine in order to provide access to
+# keystore keys.
+ifneq (,$(wildcard external/boringssl/flavor.mk))
+LOCAL_SHARED_LIBRARIES += libkeystore-engine
+endif
+
ifdef CONFIG_DRIVER_NL80211
ifneq ($(wildcard external/libnl),)
LOCAL_SHARED_LIBRARIES += libnl
@@ -1618,6 +1594,13 @@ endif
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS)
LOCAL_C_INCLUDES := $(INCLUDES)
+ifeq ($(DBUS), y)
+LOCAL_SHARED_LIBRARIES += libdbus
+endif
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+LOCAL_SHARED_LIBRARIES += libbinder libutils
+LOCAL_STATIC_LIBRARIES += libwpa_binder libwpa_binder_interface
+endif
include $(BUILD_EXECUTABLE)
########################
@@ -1656,3 +1639,42 @@ LOCAL_COPY_HEADERS_TO := libwpa_client
LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
LOCAL_COPY_HEADERS += src/common/qca-vendor.h
include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+### Binder interface library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder_interface
+LOCAL_AIDL_INCLUDES := \
+ $(LOCAL_PATH)/binder \
+ frameworks/native/aidl/binder
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_SRC_FILES := \
+ binder/binder_constants.cpp \
+ binder/fi/w1/wpa_supplicant/ISupplicant.aidl \
+ binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl \
+ binder/fi/w1/wpa_supplicant/IIface.aidl
+LOCAL_SHARED_LIBRARIES := libbinder
+include $(BUILD_STATIC_LIBRARY)
+
+### Binder service library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_SRC_FILES := \
+ binder/binder.cpp binder/binder_manager.cpp \
+ binder/supplicant.cpp binder/iface.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libutils
+LOCAL_STATIC_LIBRARIES := libwpa_binder_interface
+include $(BUILD_STATIC_LIBRARY)
+
+endif # BINDER == y
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index facd90e..f28055f 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,149 @@
ChangeLog for wpa_supplicant
+2016-10-02 - v2.6
+ * fixed WNM Sleep Mode processing when PMF is not enabled
+ [http://w1.fi/security/2015-6/] (CVE-2015-5310)
+ * fixed EAP-pwd last fragment validation
+ [http://w1.fi/security/2015-7/] (CVE-2015-5315)
+ * fixed EAP-pwd unexpected Confirm message processing
+ [http://w1.fi/security/2015-8/] (CVE-2015-5316)
+ * fixed WPS configuration update vulnerability with malformed passphrase
+ [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+ * fixed configuration update vulnerability with malformed parameters set
+ over the local control interface
+ [http://w1.fi/security/2016-1/] (CVE-2016-4477)
+ * fixed TK configuration to the driver in EAPOL-Key 3/4 retry case
+ * extended channel switch support for P2P GO
+ * started to throttle control interface event message bursts to avoid
+ issues with monitor sockets running out of buffer space
+ * mesh mode fixes/improvements
+ - generate proper AID for peer
+ - enable WMM by default
+ - add VHT support
+ - fix PMKID derivation
+ - improve robustness on various exchanges
+ - fix peer link counting in reconnect case
+ - improve mesh joining behavior
+ - allow DTIM period to be configured
+ - allow HT to be disabled (disable_ht=1)
+ - add MESH_PEER_ADD and MESH_PEER_REMOVE commands
+ - add support for PMKSA caching
+ - add minimal support for SAE group negotiation
+ - allow pairwise/group cipher to be configured in the network profile
+ - use ieee80211w profile parameter to enable/disable PMF and derive
+ a separate TX IGTK if PMF is enabled instead of using MGTK
+ incorrectly
+ - fix AEK and MTK derivation
+ - remove GTKdata and IGTKdata from Mesh Peering Confirm/Close
+ - note: these changes are not fully backwards compatible for secure
+ (RSN) mesh network
+ * fixed PMKID derivation with SAE
+ * added support for requesting and fetching arbitrary ANQP-elements
+ without internal support in wpa_supplicant for the specific element
+ (anqp[265]=<hexdump> in "BSS <BSSID>" command output)
+ * P2P
+ - filter control characters in group client device names to be
+ consistent with other P2P peer cases
+ - support VHT 80+80 MHz and 160 MHz
+ - indicate group completion in P2P Client role after data association
+ instead of already after the WPS provisioning step
+ - improve group-join operation to use SSID, if known, to filter BSS
+ entries
+ - added optional ssid=<hexdump> argument to P2P_CONNECT for join case
+ - added P2P_GROUP_MEMBER command to fetch client interface address
+ * P2PS
+ - fix follow-on PD Response behavior
+ - fix PD Response generation for unknown peer
+ - fix persistent group reporting
+ - add channel policy to PD Request
+ - add group SSID to the P2PS-PROV-DONE event
+ - allow "P2P_CONNECT <addr> p2ps" to be used without specifying the
+ default PIN
+ * BoringSSL
+ - support for OCSP stapling
+ - support building of h20-osu-client
+ * D-Bus
+ - add ExpectDisconnect()
+ - add global config parameters as properties
+ - add SaveConfig()
+ - add VendorElemAdd(), VendorElemGet(), VendorElemRem()
+ * fixed Suite B 192-bit AKM to use proper PMK length
+ (note: this makes old releases incompatible with the fixed behavior)
+ * improved PMF behavior for cases where the AP and STA has different
+ configuration by not trying to connect in some corner cases where the
+ connection cannot succeed
+ * added option to reopen debug log (e.g., to rotate the file) upon
+ receipt of SIGHUP signal
+ * EAP-pwd: added support for Brainpool Elliptic Curves
+ (with OpenSSL 1.0.2 and newer)
+ * fixed EAPOL reauthentication after FT protocol run
+ * fixed FTIE generation for 4-way handshake after FT protocol run
+ * extended INTERFACE_ADD command to allow certain type (sta/ap)
+ interface to be created
+ * fixed and improved various FST operations
+ * added 80+80 MHz and 160 MHz VHT support for IBSS/mesh
+ * fixed SIGNAL_POLL in IBSS and mesh cases
+ * added an option to abort an ongoing scan (used to speed up connection
+ and can also be done with the new ABORT_SCAN command)
+ * TLS client
+ - do not verify CA certificates when ca_cert is not specified
+ - support validating server certificate hash
+ - support SHA384 and SHA512 hashes
+ - add signature_algorithms extension into ClientHello
+ - support TLS v1.2 signature algorithm with SHA384 and SHA512
+ - support server certificate probing
+ - allow specific TLS versions to be disabled with phase2 parameter
+ - support extKeyUsage
+ - support PKCS #5 v2.0 PBES2
+ - support PKCS #5 with PKCS #12 style key decryption
+ - minimal support for PKCS #12
+ - support OCSP stapling (including ocsp_multi)
+ * OpenSSL
+ - support OpenSSL 1.1 API changes
+ - drop support for OpenSSL 0.9.8
+ - drop support for OpenSSL 1.0.0
+ * added support for multiple schedule scan plans (sched_scan_plans)
+ * added support for external server certificate chain validation
+ (tls_ext_cert_check=1 in the network profile phase1 parameter)
+ * made phase2 parser more strict about correct use of auth=<val> and
+ autheap=<val> values
+ * improved GAS offchannel operations with comeback request
+ * added SIGNAL_MONITOR command to request signal strength monitoring
+ events
+ * added command for retrieving HS 2.0 icons with in-memory storage
+ (REQ_HS20_ICON, GET_HS20_ICON, DEL_HS20_ICON commands and
+ RX-HS20-ICON event)
+ * enabled ACS support for AP mode operations with wpa_supplicant
+ * EAP-PEAP: fixed interoperability issue with Windows 2012r2 server
+ ("Invalid Compound_MAC in cryptobinding TLV")
+ * EAP-TTLS: fixed success after fragmented final Phase 2 message
+ * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+ * WNM: workaround for broken AP operating class behavior
+ * added kqueue(2) support for eloop (CONFIG_ELOOP_KQUEUE)
+ * nl80211:
+ - add support for full station state operations
+ - do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled
+ - add NL80211_ATTR_PREV_BSSID with Connect command
+ - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+ unencrypted EAPOL frames
+ * added initial MBO support; number of extensions to WNM BSS Transition
+ Management
+ * added support for PBSS/PCP and P2P on 60 GHz
+ * Interworking: add credential realm to EAP-TLS identity
+ * fixed EAPOL-Key Request Secure bit to be 1 if PTK is set
+ * HS 2.0: add support for configuring frame filters
+ * added POLL_STA command to check connectivity in AP mode
+ * added initial functionality for location related operations
+ * started to ignore pmf=1/2 parameter for non-RSN networks
+ * added wps_disabled=1 network profile parameter to allow AP mode to
+ be started without enabling WPS
+ * wpa_cli: added action script support for AP-ENABLED and AP-DISABLED
+ events
+ * improved Public Action frame addressing
+ - add gas_address3 configuration parameter to control Address 3
+ behavior
+ * number of small fixes
+
2015-09-27 - v2.5
* fixed P2P validation of SSID element length before copying it
[http://w1.fi/security/2015-1/] (CVE-2015-1863)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index ad9ead9..f3e86c1 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -6,6 +6,17 @@ ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
+ifdef LIBS
+# If LIBS is set with some global build system defaults, clone those for
+# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
+ifndef LIBS_c
+LIBS_c := $(LIBS)
+endif
+ifndef LIBS_p
+LIBS_p := $(LIBS)
+endif
+endif
+
export LIBDIR ?= /usr/local/lib/
export INCDIR ?= /usr/local/include/
export BINDIR ?= /usr/local/sbin/
@@ -17,6 +28,16 @@ CFLAGS += -I$(abspath ../src/utils)
-include .config
+ifndef CONFIG_NO_GITVER
+# Add VERSION_STR postfix for builds from a git repository
+ifeq ($(wildcard ../.git),../.git)
+GITVER := $(shell git describe --dirty=+)
+ifneq ($(GITVER),)
+CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
+endif
+endif
+endif
+
ifdef CONFIG_TESTING_OPTIONS
CFLAGS += -DCONFIG_TESTING_OPTIONS
CONFIG_WPS_TESTING=y
@@ -89,6 +110,7 @@ OBJS_p += ../src/utils/wpabuf.o
OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
OBJS_c += ../src/utils/wpa_debug.o
OBJS_c += ../src/utils/common.o
+OBJS_c += ../src/common/cli.o
OBJS += wmm_ac.o
ifndef CONFIG_OS
@@ -149,6 +171,10 @@ ifdef CONFIG_ELOOP_EPOLL
CFLAGS += -DCONFIG_ELOOP_EPOLL
endif
+ifdef CONFIG_ELOOP_KQUEUE
+CFLAGS += -DCONFIG_ELOOP_KQUEUE
+endif
+
ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
@@ -278,14 +304,23 @@ NEED_MD5=y
NEED_RC4=y
else
CFLAGS += -DCONFIG_NO_WPA
+ifeq ($(CONFIG_TLS), internal)
+NEED_SHA1=y
+NEED_MD5=y
+endif
endif
ifdef CONFIG_IBSS_RSN
NEED_RSN_AUTHENTICATOR=y
CFLAGS += -DCONFIG_IBSS_RSN
+CFLAGS += -DCONFIG_NO_VLAN
OBJS += ibss_rsn.o
endif
+ifdef CONFIG_MATCH_IFACE
+CFLAGS += -DCONFIG_MATCH_IFACE
+endif
+
ifdef CONFIG_P2P
OBJS += p2p_supplicant.o
OBJS += p2p_supplicant_sd.o
@@ -386,7 +421,6 @@ EAPDYN += ../src/eap_peer/eap_tls.so
else
CFLAGS += -DEAP_TLS
OBJS += ../src/eap_peer/eap_tls.o
-OBJS_h += ../src/eap_server/eap_server_tls.o
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -397,7 +431,6 @@ ifdef CONFIG_EAP_UNAUTH_TLS
CFLAGS += -DEAP_UNAUTH_TLS
ifndef CONFIG_EAP_TLS
OBJS += ../src/eap_peer/eap_tls.o
-OBJS_h += ../src/eap_server/eap_server_tls.o
TLS_FUNCS=y
endif
CONFIG_IEEE8021X_EAPOL=y
@@ -412,7 +445,6 @@ else
CFLAGS += -DEAP_PEAP
OBJS += ../src/eap_peer/eap_peap.o
OBJS += ../src/eap_common/eap_peap_common.o
-OBJS_h += ../src/eap_server/eap_server_peap.o
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -426,7 +458,6 @@ EAPDYN += ../src/eap_peer/eap_ttls.so
else
CFLAGS += -DEAP_TTLS
OBJS += ../src/eap_peer/eap_ttls.o
-OBJS_h += ../src/eap_server/eap_server_ttls.o
endif
TLS_FUNCS=y
ifndef CONFIG_FIPS
@@ -444,7 +475,6 @@ EAPDYN += ../src/eap_peer/eap_md5.so
else
CFLAGS += -DEAP_MD5
OBJS += ../src/eap_peer/eap_md5.o
-OBJS_h += ../src/eap_server/eap_server_md5.o
endif
CHAP=y
CONFIG_IEEE8021X_EAPOL=y
@@ -467,7 +497,6 @@ else
CFLAGS += -DEAP_MSCHAPv2
OBJS += ../src/eap_peer/eap_mschapv2.o
OBJS += ../src/eap_peer/mschapv2.o
-OBJS_h += ../src/eap_server/eap_server_mschapv2.o
endif
MS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -481,7 +510,6 @@ EAPDYN += ../src/eap_peer/eap_gtc.so
else
CFLAGS += -DEAP_GTC
OBJS += ../src/eap_peer/eap_gtc.o
-OBJS_h += ../src/eap_server/eap_server_gtc.o
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -506,7 +534,6 @@ EAPDYN += ../src/eap_peer/eap_sim.so
else
CFLAGS += -DEAP_SIM
OBJS += ../src/eap_peer/eap_sim.o
-OBJS_h += ../src/eap_server/eap_server_sim.o
endif
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_SIM_COMMON=y
@@ -534,7 +561,6 @@ EAPDYN += ../src/eap_peer/eap_psk.so
else
CFLAGS += -DEAP_PSK
OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o
-OBJS_h += ../src/eap_server/eap_server_psk.o
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
@@ -551,7 +577,6 @@ EAPDYN += ../src/eap_peer/eap_aka.so
else
CFLAGS += -DEAP_AKA
OBJS += ../src/eap_peer/eap_aka.o
-OBJS_h += ../src/eap_server/eap_server_aka.o
endif
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_SIM_COMMON=y
@@ -577,7 +602,6 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += ../src/eap_common/eap_sim_common.o
-OBJS_h += ../src/eap_server/eap_sim_db.o
NEED_AES=y
NEED_FIPS186_2_PRF=y
endif
@@ -592,7 +616,6 @@ else
CFLAGS += -DEAP_FAST
OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
OBJS += ../src/eap_common/eap_fast_common.o
-OBJS_h += ../src/eap_server/eap_server_fast.o
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -607,7 +630,6 @@ EAPDYN += ../src/eap_peer/eap_pax.so
else
CFLAGS += -DEAP_PAX
OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o
-OBJS_h += ../src/eap_server/eap_server_pax.o
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -620,7 +642,6 @@ EAPDYN += ../src/eap_peer/eap_sake.so
else
CFLAGS += -DEAP_SAKE
OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o
-OBJS_h += ../src/eap_server/eap_server_sake.o
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -633,7 +654,6 @@ EAPDYN += ../src/eap_peer/eap_gpsk.so
else
CFLAGS += -DEAP_GPSK
OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
-OBJS_h += ../src/eap_server/eap_server_gpsk.o
endif
CONFIG_IEEE8021X_EAPOL=y
ifdef CONFIG_EAP_GPSK_SHA256
@@ -646,7 +666,6 @@ endif
ifdef CONFIG_EAP_PWD
CFLAGS += -DEAP_PWD
OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
-OBJS_h += ../src/eap_server/eap_server_pwd.o
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
endif
@@ -659,7 +678,6 @@ EAPDYN += ../src/eap_peer/eap_eke.so
else
CFLAGS += -DEAP_EKE
OBJS += ../src/eap_peer/eap_eke.o ../src/eap_common/eap_eke_common.o
-OBJS_h += ../src/eap_server/eap_server_eke.o
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
@@ -682,7 +700,6 @@ OBJS += ../src/wps/wps_attr_process.o
OBJS += ../src/wps/wps_dev_attr.o
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
-OBJS_h += ../src/eap_server/eap_server_wsc.o
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_SHA256=y
@@ -745,8 +762,6 @@ else
CFLAGS += -DEAP_IKEV2
OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o
OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
-OBJS_h += ../src/eap_server/eap_server_ikev2.o
-OBJS_h += ../src/eap_server/ikev2.o
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
@@ -762,7 +777,6 @@ EAPDYN += ../src/eap_peer/eap_vendor_test.so
else
CFLAGS += -DEAP_VENDOR_TEST
OBJS += ../src/eap_peer/eap_vendor_test.o
-OBJS_h += ../src/eap_server/eap_server_vendor_test.o
endif
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -772,8 +786,6 @@ ifdef CONFIG_EAP_TNC
CFLAGS += -DEAP_TNC
OBJS += ../src/eap_peer/eap_tnc.o
OBJS += ../src/eap_peer/tncc.o
-OBJS_h += ../src/eap_server/eap_server_tnc.o
-OBJS_h += ../src/eap_server/tncs.o
NEED_BASE64=y
ifndef CONFIG_NATIVE_WINDOWS
ifndef CONFIG_DRIVER_BSD
@@ -833,6 +845,8 @@ OBJS += ../src/ap/ap_drv_ops.o
OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/bss_load.o
OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/neighbor_db.o
+OBJS += ../src/ap/rrm.o
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
ifdef CONFIG_IEEE80211AC
@@ -842,6 +856,9 @@ endif
ifdef CONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
endif
+ifdef CONFIG_MBO
+OBJS += ../src/ap/mbo_ap.o
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += ../src/ap/ctrl_iface_ap.o
endif
@@ -858,6 +875,11 @@ CFLAGS += -DCONFIG_IEEE80211AC
endif
endif
+ifdef CONFIG_MBO
+OBJS += mbo.o
+CFLAGS += -DCONFIG_MBO
+endif
+
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
@@ -893,34 +915,10 @@ OBJS += ../src/ap/peerkey_auth.o
endif
endif
-ifdef CONFIG_EAP_SERVER
-CFLAGS += -DEAP_SERVER
-OBJS_h += ../src/eap_server/eap_server.o
-OBJS_h += ../src/eap_server/eap_server_identity.o
-OBJS_h += ../src/eap_server/eap_server_methods.o
-endif
-
-ifdef CONFIG_RADIUS_CLIENT
-OBJS_h += ../src/utils/ip_addr.o
-OBJS_h += ../src/radius/radius.o
-OBJS_h += ../src/radius/radius_client.o
-endif
-
-ifdef CONFIG_AUTHENTICATOR
-OBJS_h += ../src/eapol_auth/eapol_auth_sm.o
-OBJS_h += ../src/ap/ieee802_1x.o
-endif
-
-ifdef CONFIG_WPA_AUTHENTICATOR
-OBJS_h += ../src/ap/wpa_auth.o
-OBJS_h += ../src/ap/wpa_auth_ie.o
-OBJS_h += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R
-OBJS_h += ../src/ap/wpa_auth_ft.o
-endif
-ifdef CONFIG_PEERKEY
-OBJS_h += ../src/ap/peerkey_auth.o
-endif
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
endif
ifdef CONFIG_PCSC
@@ -933,9 +931,13 @@ ifdef CONFIG_NATIVE_WINDOWS
#dynamic symbol loading that is now used in pcsc_funcs.c
#LIBS += -lwinscard
else
+ifdef CONFIG_OSX
+LIBS += -framework PCSC
+else
LIBS += -lpcsclite -lpthread
endif
endif
+endif
ifdef CONFIG_SIM_SIMULATOR
CFLAGS += -DCONFIG_SIM_SIMULATOR
@@ -974,7 +976,6 @@ ifdef TLS_FUNCS
NEED_DES=y
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += ../src/eap_peer/eap_tls_common.o
-OBJS_h += ../src/eap_server/eap_server_tls_common.o
ifndef CONFIG_FIPS
NEED_TLS_PRF=y
NEED_SHA1=y
@@ -999,6 +1000,7 @@ ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../src/crypto/tls_openssl.o
+OBJS += ../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl
endif
OBJS += ../src/crypto/crypto_openssl.o
@@ -1049,6 +1051,7 @@ OBJS += ../src/tls/tlsv1_cred.o
OBJS += ../src/tls/tlsv1_client.o
OBJS += ../src/tls/tlsv1_client_write.o
OBJS += ../src/tls/tlsv1_client_read.o
+OBJS += ../src/tls/tlsv1_client_ocsp.o
OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
@@ -1102,6 +1105,8 @@ CONFIG_INTERNAL_SHA1=y
CONFIG_INTERNAL_MD4=y
CONFIG_INTERNAL_MD5=y
CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
@@ -1287,10 +1292,19 @@ SHA256OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += ../src/crypto/sha256-internal.o
endif
+ifdef CONFIG_INTERNAL_SHA384
+CFLAGS += -DCONFIG_INTERNAL_SHA384
+SHA256OBJS += ../src/crypto/sha384-internal.o
+endif
+ifdef CONFIG_INTERNAL_SHA512
+CFLAGS += -DCONFIG_INTERNAL_SHA512
+SHA256OBJS += ../src/crypto/sha512-internal.o
+endif
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += ../src/crypto/sha256-tlsprf.o
endif
ifdef NEED_HMAC_SHA256_KDF
+CFLAGS += -DCONFIG_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
endif
OBJS += $(SHA256OBJS)
@@ -1333,6 +1347,7 @@ endif
CFLAGS += -DCONFIG_CTRL_IFACE
ifeq ($(CONFIG_CTRL_IFACE), unix)
CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+OBJS += ../src/common/ctrl_iface_common.o
endif
ifeq ($(CONFIG_CTRL_IFACE), udp)
CFLAGS += -DCONFIG_CTRL_IFACE_UDP
@@ -1374,6 +1389,7 @@ ifndef DBUS_INCLUDE
DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
endif
DBUS_CFLAGS += $(DBUS_INCLUDE)
+DBUS_INTERFACE=fi.epitest.hostap.WPASupplicant
endif
ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -1399,6 +1415,7 @@ DBUS_OBJS += dbus/dbus_new_introspect.o
DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
endif
DBUS_CFLAGS += $(DBUS_INCLUDE)
+DBUS_INTERFACE=fi.w1.wpa_supplicant1
endif
ifdef DBUS
@@ -1412,7 +1429,7 @@ LIBS += $(DBUS_LIBS)
ifdef CONFIG_READLINE
OBJS_c += ../src/utils/edit_readline.o
-LIBS_c += -lncurses -lreadline
+LIBS_c += -lreadline -lncurses
else
ifdef CONFIG_WPA_CLI_EDIT
OBJS_c += ../src/utils/edit.o
@@ -1443,6 +1460,10 @@ ifdef CONFIG_IPV6
CFLAGS += -DCONFIG_IPV6
endif
+ifdef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+CFLAGS += -DCONFIG_NO_LINUX_PACKET_SOCKET_WAR
+endif
+
ifdef NEED_BASE64
OBJS += ../src/utils/base64.o
endif
@@ -1569,12 +1590,6 @@ endif
OBJS += ../src/drivers/driver_common.o
OBJS_priv += ../src/drivers/driver_common.o
-OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o
-OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
-ifdef CONFIG_AUTHENTICATOR
-OBJS_wpa += tests/link_test.o
-endif
-OBJS_wpa += $(OBJS_l2)
OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
@@ -1636,6 +1651,7 @@ endif
OBJS += $(FST_OBJS)
OBJS_t += $(FST_OBJS)
OBJS_t2 += $(FST_OBJS)
+OBJS_nfc += $(FST_OBJS)
endif
ifndef LDO
@@ -1691,9 +1707,11 @@ wpa_cli: $(OBJS_c)
LIBCTRL += ../src/common/wpa_ctrl.o
LIBCTRL += ../src/utils/os_$(CONFIG_OS).o
+LIBCTRL += ../src/utils/common.o
LIBCTRL += ../src/utils/wpa_debug.o
LIBCTRLSO += ../src/common/wpa_ctrl.c
LIBCTRLSO += ../src/utils/os_$(CONFIG_OS).c
+LIBCTRLSO += ../src/utils/common.c
LIBCTRLSO += ../src/utils/wpa_debug.c
libwpa_client.a: $(LIBCTRL)
@@ -1705,12 +1723,12 @@ libwpa_client.so: $(LIBCTRLSO)
@$(E) " CC $@ ($^)"
$(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^
-link_test: $(OBJS) $(OBJS_h) tests/link_test.o
- $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+libwpa_test1: libwpa_test.o libwpa_client.a
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 libwpa_test.o libwpa_client.a $(LIBS_c)
@$(E) " LD " $@
-test_wpa: $(OBJS_wpa) $(OBJS_h)
- $(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+libwpa_test2: libwpa_test.o libwpa_client.so
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 libwpa_test.o -L. -lwpa_client $(LIBS_c)
@$(E) " LD " $@
nfc_pw_token: $(OBJS_nfc)
@@ -1760,11 +1778,13 @@ else
endif
%.service: %.service.in
- $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
+ -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
@$(E) " sed" $<
%@.service: %.service.arg.in
- $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
+ -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
@$(E) " sed" $<
wpa_supplicant.exe: wpa_supplicant
@@ -1795,17 +1815,6 @@ wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts
wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm
$(MAKE) -C wpa_gui-qt4
-TEST_EAP_SIM_COMMON_OBJS = $(SHA1OBJS) $(MD5OBJS) \
- ../src/utils/common.o ../src/utils/os_unix.o \
- ../src/utils/wpa_debug.o $(AESOBJS) \
- tests/test_eap_sim_common.o
-test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
- $(LDO) $(LDFLAGS) -o $@ $(TEST_EAP_SIM_COMMON_OBJS) $(LIBS)
- ./test-eap_sim_common
- rm test-eap_sim_common
-
-tests: test-eap_sim_common
-
FIPSDIR=/usr/local/ssl/fips-2.0
FIPSLD=$(FIPSDIR)/bin/fipsld
fips:
@@ -1826,5 +1835,6 @@ clean:
rm -rf lcov-html
rm -f libwpa_client.a
rm -f libwpa_client.so
+ rm -f libwpa_test1 libwpa_test2
-include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index f9c65d2..11ab01a 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -72,11 +72,13 @@ Supported WPA/IEEE 802.11i features:
* EAP-TTLS/CHAP
* EAP-SIM
* EAP-AKA
+ * EAP-AKA'
* EAP-PSK
* EAP-PAX
* EAP-SAKE
* EAP-IKEv2
* EAP-GPSK
+ * EAP-pwd
* LEAP (note: requires special support from the driver for IEEE 802.11
authentication)
(following methods are supported, but since they do not generate keying
@@ -163,18 +165,12 @@ systems. In case of Windows builds, WinPcap is used by default
Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS:
-- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to
+- OpenSSL (tested with 1.0.1 and 1.0.2 versions; assumed to
work with most relatively recent versions; this is likely to be
available with most distributions, http://www.openssl.org/)
- GnuTLS
- internal TLSv1 implementation
-TLS options for EAP-FAST:
-- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied
- (i.e., the default OpenSSL package does not include support for
- extensions needed for EAP-FAST)
-- internal TLSv1 implementation
-
One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or
EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
implementation. A configuration file, .config, for compilation is
@@ -308,7 +304,7 @@ Following build time configuration options are used to control IEEE
802.1X/EAPOL and EAP state machines and all EAP methods. Including
TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL
library for TLS implementation. Alternatively, GnuTLS or the internal
-TLSv1 implementation can be used for TLS functionaly.
+TLSv1 implementation can be used for TLS functionality.
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_MD5=y
@@ -320,15 +316,17 @@ CONFIG_EAP_GTC=y
CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
+CONFIG_EAP_AKA_PRIME=y
CONFIG_EAP_PSK=y
CONFIG_EAP_SAKE=y
CONFIG_EAP_GPSK=y
CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
CONFIG_EAP_IKEV2=y
+CONFIG_EAP_PWD=y
Following option can be used to include GSM SIM/USIM interface for GSM/UMTS
-authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
+authentication algorithm (for EAP-SIM/EAP-AKA/EAP-AKA'). This requires pcsc-lite
(http://www.linuxnet.com/) for smart card access.
CONFIG_PCSC=y
@@ -409,10 +407,10 @@ Command line options
--------------------
usage:
- wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
+ wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
[-G<group>] \
-i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
- [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+ [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
[-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
options:
@@ -435,8 +433,8 @@ options:
-q = decrease debugging verbosity (-qq even less)
-u = enable DBus control interface
-v = show version
- -w = wait for interface to be added, if needed
-W = wait for a control interface monitor before starting
+ -M = start describing matching interface
-N = start describing new interface
-m = Configuration file for the P2P Device
@@ -479,6 +477,22 @@ wpa_supplicant \
-c wpa2.conf -i wlan1 -D wext
+If the interfaces on which wpa_supplicant is to run are not known or do
+not exist, wpa_supplicant can match an interface when it arrives. Each
+matched interface is separated with -M argument and the -i argument now
+allows for pattern matching.
+
+As an example, the following command would start wpa_supplicant for a
+specific wired interface called lan0, any interface starting with wlan
+and lastly any other interface. Each match has its own configuration
+file, and for the wired interface a specific driver has also been given.
+
+wpa_supplicant \
+ -M -c wpa_wired.conf -ilan0 -D wired \
+ -M -c wpa1.conf -iwlan* \
+ -M -c wpa2.conf
+
+
If the interface is added in a Linux bridge (e.g., br0), the bridge
interface needs to be configured to wpa_supplicant in addition to the
main interface:
@@ -500,7 +514,7 @@ reloading can be triggered with 'wpa_cli reconfigure' command.
Configuration file can include one or more network blocks, e.g., one
for each used SSID. wpa_supplicant will automatically select the best
-betwork based on the order of network blocks in the configuration
+network based on the order of network blocks in the configuration
file, network security level (WPA/WPA2 is preferred), and signal
strength.
@@ -792,7 +806,7 @@ addresses, etc.
One wpa_cli process in "action" mode needs to be started for each
interface. For example, the following command starts wpa_cli for the
-default ingterface (-i can be used to select the interface in case of
+default interface (-i can be used to select the interface in case of
more than one interface being used at the same time):
wpa_cli -a/sbin/wpa_action.sh -B
@@ -1008,8 +1022,8 @@ event message is indicated that the external processing can start. Once
the operation has been completed, "RADIO_WORK done <id>" is used to
indicate that to wpa_supplicant. This allows other radio works to be
performed. If this command is forgotten (e.g., due to the external
-program terminating), wpa_supplicant will time out the radio owrk item
-and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has
+program terminating), wpa_supplicant will time out the radio work item
+and send "EXT-RADIO-WORK-TIMEOUT <id>" event to indicate that this has
happened. "RADIO_WORK done <id>" can also be used to cancel items that
have not yet been started.
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 161dc06..e4eed20 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -229,7 +229,7 @@ Credentials can be pre-configured for automatic network selection:
#
# sp_priority: Credential priority within a provisioning SP
# This is the priority of the credential among all credentials
-# provisionined by the same SP (i.e., for entries that have identical
+# provisioned by the same SP (i.e., for entries that have identical
# provisioning_sp value). The range of this priority is 0-255 with 0
# being the highest and 255 the lower priority.
#
@@ -564,3 +564,68 @@ OK
<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
<3>ANQP fetch completed
+
+
+Hotspot 2.0 Rel 2 online signup and OSEN
+----------------------------------------
+
+Following parameters can be used to create a network profile for
+link-layer protected Hotspot 2.0 online signup connection with
+OSEN. Note that ssid and identify (NAI) values need to be set based on
+the information for the selected provider in the OSU Providers list
+ANQP-element.
+
+network={
+ ssid="HS 2.0 OSU"
+ proto=OSEN
+ key_mgmt=OSEN
+ pairwise=CCMP
+ group=GTK_NOT_USED
+ eap=WFA-UNAUTH-TLS
+ identity="anonymous@example.com"
+ ca_cert="osu-ca.pem"
+ ocsp=2
+}
+
+
+Hotspot 2.0 connection with external network selection
+------------------------------------------------------
+
+When an component controlling wpa_supplicant takes care of Interworking
+network selection, following configuration and network profile
+parameters can be used to configure a temporary network profile for a
+Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and
+SELECT_NETWORK control interface commands):
+
+interworking=1
+hs20=1
+auto_interworking=0
+
+network={
+ ssid="test-hs20"
+ proto=RSN
+ key_mgmt=WPA-EAP
+ pairwise=CCMP
+ anonymous_identity="anonymous@example.com"
+ identity="hs20-test@example.com"
+ password="password"
+ ca_cert="ca.pem"
+ eap=TTLS
+ phase2="auth=MSCHAPV2"
+ update_identifier=54321
+ #ocsp=2
+}
+
+
+These parameters are set based on the PPS MO credential and/or NAI Realm
+list ANQP-element:
+
+anonymous_identity: Credential/UsernamePassword/Username with username part
+ replaced with "anonymous"
+identity: Credential/UsernamePassword/Username
+password: Credential/UsernamePassword/Password
+update_identifier: PPS/UpdateIdentifier
+ca_cert: from the downloaded trust root based on PPS information
+eap: Credential/UsernamePassword/EAPMethod or NAI Realm list
+phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list
+ocsp: Credential/CheckAAAServerCertStatus
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 6a5b032..23ac7fa 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -151,6 +151,7 @@ join-a-group style PD instead of GO Negotiation style PD.
p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps]
[persistent|persistent=<network id>] [join|auth]
[go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
+ [ssid=<hexdump>]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -195,11 +196,17 @@ connection.
out whether the peer device is operating as a GO and if so, use
join-a-group operation rather than GO Negotiation.
+"ssid=<hexdump>" can be used to specify the Group SSID for join
+operations. This allows the P2P Client interface to filter scan results
+based on SSID to avoid selecting an incorrect BSS entry in case the same
+P2P Device or Interface address have been used in multiple groups
+recently.
+
P2PS attribute changes to p2p_connect command:
P2PS supports two WPS provisioning methods namely PIN method and P2PS default.
-The remaining paramters hold same role as in legacy P2P. In case of P2PS default
-config method "p2ps" keyword is added in p2p_connect command.
+The remaining parameters hold same role as in legacy P2P. In case of P2PS
+default config method "p2ps" keyword is added in p2p_connect command.
For example:
p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join
@@ -281,7 +288,7 @@ group interface is used as a parameter for this command.
p2p_cancel
Cancel an ongoing P2P group formation and joining-a-group related
-operation. This operations unauthorizes the specific peer device (if any
+operation. This operation unauthorizes the specific peer device (if any
had been authorized to start group formation), stops P2P find (if in
progress), stops pending operations for join-a-group, and removes the
P2P group interface (if one was used) that is in the WPS provisioning
@@ -633,12 +640,17 @@ p2p_set managed <0/1>
Disable/enable managed P2P Device operations. This is disabled by
default.
-p2p_set listen_channel <1/6/11>
+p2p_set listen_channel <channel> [<op_class>]
Set P2P Listen channel. This is mainly meant for testing purposes and
changing the Listen channel during normal operations can result in
protocol failures.
+When specifying a social channel on the 2.4 GHz band (1/6/11) there is
+no need to specify the operating class since it defaults to 81. When
+specifying a social channel on the 60 GHz band (2), specify the 60 GHz
+operating class (180).
+
p2p_set ssid_postfix <postfix>
Set postfix string to be added to the automatically generated P2P SSID
@@ -650,7 +662,7 @@ p2p_set per_sta_psk <0/1>
Disabled(default)/enables use of per-client PSK in the P2P groups. This
can be used to request GO to assign a unique PSK for each client during
WPS provisioning. When enabled, this allow clients to be removed from
-the group securily with p2p_remove_client command since that client's
+the group securely with p2p_remove_client command since that client's
PSK is removed at the same time to prevent it from connecting back using
the old PSK. When per-client PSK is not used, the client can still be
disconnected, but it will be able to re-join the group since the PSK it
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 6c3ee6d..02505bb 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -32,6 +32,9 @@
#CONFIG_DRIVER_NL80211=y
CONFIG_LIBNL20=y
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=y
+
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -92,7 +95,7 @@ CONFIG_EAP_TTLS=y
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
# to add the needed functions.
-CONFIG_EAP_FAST=y
+#CONFIG_EAP_FAST=y
# EAP-GTC
CONFIG_EAP_GTC=y
@@ -321,6 +324,10 @@ CONFIG_IEEE80211W=y
# Add introspection support for new DBus control interface
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+# Add support for Binder control interface
+# Only applicable for Android platforms.
+#CONFIG_CTRL_IFACE_BINDER=y
+
# Add support for loading EAP methods dynamically as shared libraries.
# When this option is enabled, each EAP method can be either included
# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
@@ -479,4 +486,7 @@ CONFIG_WIFI_DISPLAY=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
+# Support Multi Band Operation
+#CONFIG_MBO=y
+
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 7a4f4cf..5afb772 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -56,12 +56,32 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
if (!conf->secondary_channel)
goto no_vht;
- center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ switch (conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ case VHT_CHANWIDTH_80P80MHZ:
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+ break;
+ default:
+ /*
+ * conf->vht_oper_chwidth might not be set for non-P2P GO cases,
+ * try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
+ * not supported.
+ */
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+ if (!center_chan) {
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
+ channel);
+ }
+ break;
+ }
if (!center_chan)
goto no_vht;
- /* Use 80 MHz channel */
- conf->vht_oper_chwidth = 1;
conf->vht_oper_centr_freq_seg0_idx = center_chan;
return;
@@ -72,14 +92,24 @@ no_vht:
conf->vht_oper_centr_freq_seg0_idx =
conf->channel + conf->secondary_channel * 2;
#endif /* CONFIG_P2P */
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
}
#endif /* CONFIG_IEEE80211N */
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf)
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
{
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
+
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+ ssid->frequency);
+ return -1;
+ }
+
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
@@ -166,6 +196,8 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
}
}
#endif /* CONFIG_IEEE80211N */
+
+ return 0;
}
@@ -179,15 +211,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- if (conf->hw_mode == NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
- ssid->frequency);
+ if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
+ return -1;
+
+ if (ssid->pbss > 1) {
+ wpa_printf(MSG_ERROR, "Invalid pbss value(%d) for AP mode",
+ ssid->pbss);
return -1;
}
+ bss->pbss = ssid->pbss;
- wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+#ifdef CONFIG_ACS
+ if (ssid->acs) {
+ /* Setting channel to 0 in order to enable ACS */
+ conf->channel = 0;
+ wpa_printf(MSG_DEBUG, "Use automatic channel selection");
+ }
+#endif /* CONFIG_ACS */
if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
conf->ieee80211h = 1;
@@ -229,12 +269,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
if (ssid->p2p_group) {
- os_memcpy(bss->ip_addr_go, wpa_s->parent->conf->ip_addr_go, 4);
- os_memcpy(bss->ip_addr_mask, wpa_s->parent->conf->ip_addr_mask,
+ os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
+ os_memcpy(bss->ip_addr_mask, wpa_s->p2pdev->conf->ip_addr_mask,
4);
os_memcpy(bss->ip_addr_start,
- wpa_s->parent->conf->ip_addr_start, 4);
- os_memcpy(bss->ip_addr_end, wpa_s->parent->conf->ip_addr_end,
+ wpa_s->p2pdev->conf->ip_addr_start, 4);
+ os_memcpy(bss->ip_addr_end, wpa_s->p2pdev->conf->ip_addr_end,
4);
}
#endif /* CONFIG_P2P */
@@ -254,7 +294,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
bss->wpa = ssid->proto;
- bss->wpa_key_mgmt = ssid->key_mgmt;
+ if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ else
+ bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
@@ -263,6 +306,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
return -1;
os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
bss->ssid.wpa_psk->group = 1;
+ bss->ssid.wpa_psk_set = 1;
} else if (ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
@@ -297,13 +341,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
conf->beacon_int = wpa_s->conf->beacon_int;
#ifdef CONFIG_P2P
- if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
- wpa_printf(MSG_INFO,
- "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
- wpa_s->conf->p2p_go_ctwindow, conf->beacon_int);
- conf->p2p_go_ctwindow = 0;
- } else {
- conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+ if (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+ if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
+ wpa_printf(MSG_INFO,
+ "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
+ wpa_s->conf->p2p_go_ctwindow,
+ conf->beacon_int);
+ conf->p2p_go_ctwindow = 0;
+ } else {
+ conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+ }
}
#endif /* CONFIG_P2P */
@@ -372,6 +420,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
!(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
+ if (ssid->wps_disabled)
+ goto no_wps;
bss->eap_server = 1;
if (!ssid->ignore_broadcast_ssid)
@@ -400,6 +450,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
+ if (ssid->eap.fragment_size != DEFAULT_FRAGMENT_SIZE)
+ bss->fragment_size = ssid->eap.fragment_size;
no_wps:
#endif /* CONFIG_WPS */
@@ -416,6 +468,9 @@ no_wps:
wpabuf_dup(wpa_s->conf->ap_vendor_elements);
}
+ bss->ftm_responder = wpa_s->conf->ftm_responder;
+ bss->ftm_initiator = wpa_s->conf->ftm_initiator;
+
return 0;
}
@@ -448,14 +503,14 @@ static void ap_wps_event_cb(void *ctx, enum wps_event event,
if (event == WPS_EV_FAIL) {
struct wps_event_fail *fail = &data->fail;
- if (wpa_s->parent && wpa_s->parent != wpa_s &&
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s &&
wpa_s == wpa_s->global->p2p_group_formation) {
/*
* src/ap/wps_hostapd.c has already sent this on the
* main interface, so only send on the parent interface
* here if needed.
*/
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
@@ -530,6 +585,11 @@ static void wpas_ap_configured_cb(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+#ifdef CONFIG_ACS
+ if (wpa_s->current_ssid && wpa_s->current_ssid->acs)
+ wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+#endif /* CONFIG_ACS */
+
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
if (wpa_s->ap_configured_cb)
@@ -595,8 +655,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.p2p = 1;
#endif /* CONFIG_P2P */
- if (wpa_s->parent->set_ap_uapsd)
- params.uapsd = wpa_s->parent->ap_uapsd;
+ if (wpa_s->p2pdev->set_ap_uapsd)
+ params.uapsd = wpa_s->p2pdev->ap_uapsd;
else if (params.p2p && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
params.uapsd = 1; /* mandatory for P2P GO */
else
@@ -605,12 +665,17 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
if (ieee80211_is_dfs(params.freq.freq))
params.freq.freq = 0; /* set channel after CAC */
+ if (params.p2p)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS);
+
if (wpa_drv_associate(wpa_s, &params) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
}
- wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
+ wpa_s->ap_iface = hapd_iface = hostapd_alloc_iface();
if (hapd_iface == NULL)
return -1;
hapd_iface->owner = wpa_s;
@@ -627,6 +692,13 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
}
+ /* Use the maximum oper channel width if it's given. */
+ if (ssid->max_oper_chwidth)
+ conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &conf->vht_oper_centr_freq_seg1_idx);
+
os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
wpa_s->conf->wmm_ac_params,
sizeof(wpa_s->conf->wmm_ac_params));
@@ -668,7 +740,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
}
hapd_iface->bss[i]->msg_ctx = wpa_s;
- hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
+ hapd_iface->bss[i]->msg_ctx_parent = wpa_s->p2pdev;
hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
@@ -864,7 +936,10 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
return -1;
if (pin == NULL) {
- unsigned int rpin = wps_generate_pin();
+ unsigned int rpin;
+
+ if (wps_generate_pin(&rpin) < 0)
+ return -1;
ret_len = os_snprintf(buf, buflen, "%08d", rpin);
if (os_snprintf_error(buflen, ret_len))
return -1;
@@ -930,7 +1005,8 @@ const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
if (wpa_s->ap_iface == NULL)
return NULL;
hapd = wpa_s->ap_iface->bss[0];
- pin = wps_generate_pin();
+ if (wps_generate_pin(&pin) < 0)
+ return NULL;
os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(pin_txt);
@@ -1265,8 +1341,8 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
hapd = wpa_s->ap_iface->bss[0];
wps = hapd->wps;
- if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL ||
- wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) {
+ if (wpa_s->p2pdev->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->p2pdev->conf->wps_nfc_dh_privkey == NULL) {
wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
return -1;
}
@@ -1275,9 +1351,9 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
wpabuf_free(wps->dh_pubkey);
wpabuf_free(wps->dh_privkey);
wps->dh_privkey = wpabuf_dup(
- wpa_s->parent->conf->wps_nfc_dh_privkey);
+ wpa_s->p2pdev->conf->wps_nfc_dh_privkey);
wps->dh_pubkey = wpabuf_dup(
- wpa_s->parent->conf->wps_nfc_dh_pubkey);
+ wpa_s->p2pdev->conf->wps_nfc_dh_pubkey);
if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
wps->dh_ctx = NULL;
wpabuf_free(wps->dh_pubkey);
@@ -1308,6 +1384,58 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s)
hapd = wpa_s->ap_iface->bss[0];
return hostapd_ctrl_iface_stop_ap(hapd);
}
+
+
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+ size_t len)
+{
+ size_t reply_len = 0, i;
+ char ap_delimiter[] = "---- AP ----\n";
+ char mesh_delimiter[] = "---- mesh ----\n";
+ size_t dlen;
+
+ if (wpa_s->ap_iface) {
+ dlen = os_strlen(ap_delimiter);
+ if (dlen > len - reply_len)
+ return reply_len;
+ os_memcpy(&buf[reply_len], ap_delimiter, dlen);
+ reply_len += dlen;
+
+ for (i = 0; i < wpa_s->ap_iface->num_bss; i++) {
+ reply_len += hostapd_ctrl_iface_pmksa_list(
+ wpa_s->ap_iface->bss[i],
+ &buf[reply_len], len - reply_len);
+ }
+ }
+
+ if (wpa_s->ifmsh) {
+ dlen = os_strlen(mesh_delimiter);
+ if (dlen > len - reply_len)
+ return reply_len;
+ os_memcpy(&buf[reply_len], mesh_delimiter, dlen);
+ reply_len += dlen;
+
+ reply_len += hostapd_ctrl_iface_pmksa_list(
+ wpa_s->ifmsh->bss[0], &buf[reply_len],
+ len - reply_len);
+ }
+
+ return reply_len;
+}
+
+
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+
+ if (wpa_s->ap_iface) {
+ for (i = 0; i < wpa_s->ap_iface->num_bss; i++)
+ hostapd_ctrl_iface_pmksa_flush(wpa_s->ap_iface->bss[i]);
+ }
+
+ if (wpa_s->ifmsh)
+ hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]);
+}
#endif /* CONFIG_CTRL_IFACE */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 594168c..5a59ddc 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -76,12 +76,16 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
const struct wpabuf *pw, const u8 *pubkey_hash);
struct hostapd_config;
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf);
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf);
int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+ size_t len);
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+
void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar);
void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
index a2cf7a5..072a1d5 100644
--- a/wpa_supplicant/autoscan.c
+++ b/wpa_supplicant/autoscan.c
@@ -1,6 +1,7 @@
/*
* WPA Supplicant - auto scan
* Copyright (c) 2012, Intel Corporation. All rights reserved.
+ * Copyright 2015 Intel Deutschland GmbH
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,13 +16,6 @@
#include "scan.h"
#include "autoscan.h"
-#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
-extern const struct autoscan_ops autoscan_exponential_ops;
-#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
-
-#ifdef CONFIG_AUTOSCAN_PERIODIC
-extern const struct autoscan_ops autoscan_periodic_ops;
-#endif /* CONFIG_AUTOSCAN_PERIODIC */
static const struct autoscan_ops * autoscan_modules[] = {
#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
@@ -50,6 +44,11 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
size_t nlen;
int i;
const struct autoscan_ops *ops = NULL;
+ struct sched_scan_plan *scan_plans;
+
+ /* Give preference to scheduled scan plans if supported/configured */
+ if (wpa_s->sched_scan_plans)
+ return 0;
if (wpa_s->autoscan && wpa_s->autoscan_priv)
return 0;
@@ -79,11 +78,23 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
return -1;
}
+ scan_plans = os_malloc(sizeof(*wpa_s->sched_scan_plans));
+ if (!scan_plans)
+ return -1;
+
wpa_s->autoscan_params = NULL;
wpa_s->autoscan_priv = ops->init(wpa_s, params);
- if (wpa_s->autoscan_priv == NULL)
+ if (!wpa_s->autoscan_priv) {
+ os_free(scan_plans);
return -1;
+ }
+
+ scan_plans[0].interval = 5;
+ scan_plans[0].iterations = 0;
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = scan_plans;
+ wpa_s->sched_scan_plans_num = 1;
wpa_s->autoscan = ops;
wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
@@ -116,7 +127,10 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s)
wpa_s->autoscan_priv = NULL;
wpa_s->scan_interval = 5;
- wpa_s->sched_scan_interval = 0;
+
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = NULL;
+ wpa_s->sched_scan_plans_num = 0;
}
}
@@ -134,7 +148,7 @@ int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
return -1;
wpa_s->scan_interval = interval;
- wpa_s->sched_scan_interval = interval;
+ wpa_s->sched_scan_plans[0].interval = interval;
request_scan(wpa_s);
}
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
index e2a7652..560684f 100644
--- a/wpa_supplicant/autoscan.h
+++ b/wpa_supplicant/autoscan.h
@@ -27,6 +27,16 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s);
int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
+/* Available autoscan modules */
+
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+extern const struct autoscan_ops autoscan_exponential_ops;
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+extern const struct autoscan_ops autoscan_periodic_ops;
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+
#else /* CONFIG_AUTOSCAN */
static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index f74cdbf..798b43c 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -13,12 +13,6 @@
#include "config_ssid.h"
#include "bgscan.h"
-#ifdef CONFIG_BGSCAN_SIMPLE
-extern const struct bgscan_ops bgscan_simple_ops;
-#endif /* CONFIG_BGSCAN_SIMPLE */
-#ifdef CONFIG_BGSCAN_LEARN
-extern const struct bgscan_ops bgscan_learn_ops;
-#endif /* CONFIG_BGSCAN_LEARN */
static const struct bgscan_ops * bgscan_modules[] = {
#ifdef CONFIG_BGSCAN_SIMPLE
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index 9131e4e..3df1550 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -39,6 +39,15 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
int current_signal, int current_noise,
int current_txrate);
+/* Available bgscan modules */
+
+#ifdef CONFIG_BGSCAN_SIMPLE
+extern const struct bgscan_ops bgscan_simple_ops;
+#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+extern const struct bgscan_ops bgscan_learn_ops;
+#endif /* CONFIG_BGSCAN_LEARN */
+
#else /* CONFIG_BGSCAN */
static inline int bgscan_init(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/binder/.clang-format b/wpa_supplicant/binder/.clang-format
new file mode 100644
index 0000000..dbfdabf
--- /dev/null
+++ b/wpa_supplicant/binder/.clang-format
@@ -0,0 +1,9 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Mozilla
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+AccessModifierOffset: -8
+AlignAfterOpenBracket: AlwaysBreak
+SortIncludes: false
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
new file mode 100644
index 0000000..750e878
--- /dev/null
+++ b/wpa_supplicant/binder/binder.cpp
@@ -0,0 +1,104 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "binder.h"
+#include "binder_i.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+}
+
+void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_global *global = (wpa_global *)eloop_ctx;
+ struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx;
+
+ wpa_printf(
+ MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd);
+ android::IPCThreadState::self()->handlePolledCommands();
+}
+
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global)
+{
+ struct wpas_binder_priv *priv;
+ wpa_supplicant_binder::BinderManager *binder_manager;
+
+ priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv));
+ if (!priv)
+ return NULL;
+ priv->global = global;
+
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ android::IPCThreadState::self()->disableBackgroundScheduling(true);
+ android::IPCThreadState::self()->setupPolling(&priv->binder_fd);
+ wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd);
+ if (priv->binder_fd < 0)
+ goto err;
+ /* Look for read events from the binder socket in the eloop. */
+ if (eloop_register_read_sock(
+ priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0)
+ goto err;
+
+ binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ goto err;
+ binder_manager->registerBinderService(global);
+ /* We may not need to store this binder manager reference in the
+ * global data strucure because we've made it a singleton class. */
+ priv->binder_manager = (void *)binder_manager;
+
+ return priv;
+
+err:
+ wpas_binder_deinit(priv);
+ return NULL;
+}
+
+void wpas_binder_deinit(struct wpas_binder_priv *priv)
+{
+ if (!priv)
+ return;
+
+ wpa_supplicant_binder::BinderManager::destroyInstance();
+ eloop_unregister_read_sock(priv->binder_fd);
+ android::IPCThreadState::shutdown();
+}
+
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->binder)
+ return 1;
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->registerInterface(wpa_s);
+}
+
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->binder)
+ return 1;
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->unregisterInterface(wpa_s);
+}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
new file mode 100644
index 0000000..019e327
--- /dev/null
+++ b/wpa_supplicant/binder/binder.h
@@ -0,0 +1,46 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif /* _cplusplus */
+
+/**
+ * This is the binder RPC interface entry point to the wpa_supplicant core.
+ * This initializes the binder driver & BinderManager instance and then forwards
+ * all the notifcations from the supplicant core to the BinderManager.
+ */
+struct wpas_binder_priv;
+struct wpa_global;
+
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global);
+void wpas_binder_deinit(struct wpas_binder_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_BINDER
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_CTRL_IFACE_BINDER */
+static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+#endif /* CONFIG_CTRL_IFACE_BINDER */
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */
diff --git a/wpa_supplicant/binder/binder_constants.cpp b/wpa_supplicant/binder/binder_constants.cpp
new file mode 100644
index 0000000..0d452b1
--- /dev/null
+++ b/wpa_supplicant/binder/binder_constants.cpp
@@ -0,0 +1,18 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "binder_constants.h"
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+const char kServiceName[] = "wpa_supplicant";
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_constants.h b/wpa_supplicant/binder/binder_constants.h
new file mode 100644
index 0000000..a4d9b55
--- /dev/null
+++ b/wpa_supplicant/binder/binder_constants.h
@@ -0,0 +1,21 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+extern const char kServiceName[];
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */
diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h
new file mode 100644
index 0000000..5140d6d
--- /dev/null
+++ b/wpa_supplicant/binder/binder_i.h
@@ -0,0 +1,28 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_I_H
+#define BINDER_I_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+struct wpas_binder_priv
+{
+ int binder_fd;
+ struct wpa_global *global;
+ void *binder_manager;
+};
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_I_H */
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
new file mode 100644
index 0000000..27e8ded
--- /dev/null
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -0,0 +1,100 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IServiceManager.h>
+
+#include "binder_constants.h"
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+}
+
+namespace wpa_supplicant_binder {
+
+BinderManager *BinderManager::instance_ = NULL;
+
+BinderManager *BinderManager::getInstance()
+{
+ if (!instance_)
+ instance_ = new BinderManager();
+ return instance_;
+}
+
+void BinderManager::destroyInstance()
+{
+ if (instance_)
+ delete instance_;
+ instance_ = NULL;
+}
+
+int BinderManager::registerBinderService(struct wpa_global *global)
+{
+ /* Create the main binder service object and register with
+ * system service manager. */
+ supplicant_object_ = new Supplicant(global);
+ android::String16 service_name(binder_constants::kServiceName);
+ android::defaultServiceManager()->addService(
+ service_name, android::IInterface::asBinder(supplicant_object_));
+ return 0;
+}
+
+int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ /* Using the corresponding wpa_supplicant pointer as key to our
+ * object map. */
+ const void *iface_key = wpa_s;
+
+ /* Return failure if we already have an object for that iface_key. */
+ if (iface_object_map_.find(iface_key) != iface_object_map_.end())
+ return 1;
+
+ iface_object_map_[iface_key] = new Iface(wpa_s);
+ if (!iface_object_map_[iface_key].get())
+ return 1;
+
+ wpa_s->binder_object_key = iface_key;
+
+ return 0;
+}
+
+int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return 1;
+
+ const void *iface_key = wpa_s;
+ if (iface_object_map_.find(iface_key) == iface_object_map_.end())
+ return 1;
+
+ /* Delete the corresponding iface object from our map. */
+ iface_object_map_.erase(iface_key);
+ wpa_s->binder_object_key = NULL;
+ return 0;
+}
+
+int BinderManager::getIfaceBinderObjectByKey(
+ const void *iface_object_key,
+ android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+{
+ if (!iface_object_key || !iface_object)
+ return 1;
+
+ if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
+ return 1;
+
+ *iface_object = iface_object_map_[iface_object_key];
+ return 0;
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
new file mode 100644
index 0000000..d8b7dd0
--- /dev/null
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -0,0 +1,58 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+
+#include <map>
+#include <string>
+
+#include "iface.h"
+#include "supplicant.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+namespace wpa_supplicant_binder {
+
+/**
+ * BinderManager is responsible for managing the lifetime of all
+ * binder objects created by wpa_supplicant. This is a singleton
+ * class which is created by the supplicant core and can be used
+ * to get references to the binder objects.
+ */
+class BinderManager
+{
+public:
+ static BinderManager *getInstance();
+ static void destroyInstance();
+ int registerBinderService(struct wpa_global *global);
+ int registerInterface(struct wpa_supplicant *wpa_s);
+ int unregisterInterface(struct wpa_supplicant *wpa_s);
+ int getIfaceBinderObjectByKey(
+ const void *iface_object_key,
+ android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
+
+private:
+ BinderManager() = default;
+ ~BinderManager() = default;
+
+ /* Singleton instance of this class. */
+ static BinderManager *instance_;
+ /* The main binder service object. */
+ android::sp<Supplicant> supplicant_object_;
+ /* Map of all the interface specific binder objects controlled by
+ * wpa_supplicant. This map is keyed in by the corresponding
+ * wpa_supplicant structure pointer. */
+ std::map<const void *, android::sp<Iface>> iface_object_map_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
new file mode 100644
index 0000000..ea11d42
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+/**
+ * Interface exposed by wpa_supplicant for each network interface it controls.
+ */
+interface IIface {
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
new file mode 100644
index 0000000..1cbee20
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
@@ -0,0 +1,59 @@
+/*
+ * WPA Supplicant - binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+import fi.w1.wpa_supplicant.IIface;
+
+/**
+ * Interface exposed by the wpa_supplicant binder service registered
+ * with the service manager with name: fi.w1.wpa_supplicant.
+ */
+interface ISupplicant {
+ /* Error values returned by the service to RPC method calls. */
+ const int ERROR_INVALID_ARGS = 1;
+ const int ERROR_UNKNOWN = 2;
+ const int ERROR_IFACE_EXISTS = 3;
+ const int ERROR_IFACE_UNKNOWN = 4;
+
+ /**
+ * Registers a wireless interface in wpa_supplicant.
+ *
+ * @param args A dictionary with arguments used to add the interface to
+ * wpa_supplicant.
+ * The dictionary may contain the following entries:
+ * Ifname(String) Name of the network interface to control, e.g.,
+ * wlan0.
+ * BridgeIfname(String) Name of the bridge interface to control, e.g.,
+ * br0.
+ * Driver(String) Driver name which the interface uses, e.g., nl80211.
+ * ConfigFile(String) Configuration file path.
+ *
+ * @return Binder object representing the interface.
+ */
+ IIface CreateInterface(in PersistableBundle args);
+
+ /**
+ * Deregisters a wireless interface from wpa_supplicant.
+ *
+ * @param ifname Name of the network interface, e.g., wlan0
+ */
+ void RemoveInterface(in @utf8InCpp String ifname);
+
+ /**
+ * Gets a binder object for the interface corresponding to ifname
+ * which wpa_supplicant already controls.
+ *
+ * @param ifname Name of the network interface, e.g., wlan0
+ *
+ * @return Binder object representing the interface.
+ */
+ IIface GetInterface(in @utf8InCpp String ifname);
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
new file mode 100644
index 0000000..d624d91
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
@@ -0,0 +1,20 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+
+/**
+ * Callback Interface exposed by the wpa_supplicant service. Clients need
+ * to host an instance of this binder object and pass a reference of the object
+ * to wpa_supplicant via the registerCallbacksObject method.
+ */
+interface ISupplicantCallbacks {
+}
diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp
new file mode 100644
index 0000000..c61b3b0
--- /dev/null
+++ b/wpa_supplicant/binder/iface.cpp
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "iface.h"
+
+namespace wpa_supplicant_binder {
+
+Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h
new file mode 100644
index 0000000..c0ee12c
--- /dev/null
+++ b/wpa_supplicant/binder/iface.h
@@ -0,0 +1,42 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_IFACE_H
+#define WPA_SUPPLICANT_BINDER_IFACE_H
+
+#include "fi/w1/wpa_supplicant/BnIface.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of Iface binder object. Each unique binder
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class Iface : public fi::w1::wpa_supplicant::BnIface
+{
+public:
+ Iface(struct wpa_supplicant *wpa_s);
+ virtual ~Iface() = default;
+
+private:
+ /* Raw pointer to the structure maintained by the core for this
+ * interface. */
+ struct wpa_supplicant *wpa_s_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */
diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp
new file mode 100644
index 0000000..76569b1
--- /dev/null
+++ b/wpa_supplicant/binder/supplicant.cpp
@@ -0,0 +1,127 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "supplicant.h"
+#include "binder_manager.h"
+
+namespace wpa_supplicant_binder {
+
+Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {}
+
+android::binder::Status Supplicant::CreateInterface(
+ const android::os::PersistableBundle &params,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+ android::String16 driver, ifname, confname, bridge_ifname;
+
+ /* Check if required Ifname argument is missing */
+ if (!params.getString(android::String16("Ifname"), &ifname))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_INVALID_ARGS,
+ android::String8("Ifname missing in params."));
+ /* Retrieve the remaining params from the dictionary */
+ params.getString(android::String16("Driver"), &driver);
+ params.getString(android::String16("ConfigFile"), &confname);
+ params.getString(android::String16("BridgeIfname"), &bridge_ifname);
+
+ /*
+ * Try to get the wpa_supplicant record for this iface, return
+ * an error if we already control it.
+ */
+ if (wpa_supplicant_get_iface(
+ wpa_global_, android::String8(ifname).string()) != NULL)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_EXISTS,
+ android::String8("wpa_supplicant already controls this "
+ "interface."));
+
+ android::binder::Status status;
+ struct wpa_supplicant *wpa_s = NULL;
+ struct wpa_interface iface;
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.driver = os_strdup(android::String8(driver).string());
+ iface.ifname = os_strdup(android::String8(ifname).string());
+ iface.confname = os_strdup(android::String8(confname).string());
+ iface.bridge_ifname =
+ os_strdup(android::String8(bridge_ifname).string());
+ /* Otherwise, have wpa_supplicant attach to it. */
+ wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
+ /* The supplicant core creates a corresponding binder object via
+ * BinderManager when |wpa_supplicant_add_iface| is called. */
+ if (!wpa_s || !wpa_s->binder_object_key) {
+ status = android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8(
+ "wpa_supplicant couldn't grab this interface."));
+ } else {
+ BinderManager *binder_manager = BinderManager::getInstance();
+
+ if (!binder_manager ||
+ binder_manager->getIfaceBinderObjectByKey(
+ wpa_s->binder_object_key, aidl_return))
+ status =
+ android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8("wpa_supplicant encountered a "
+ "binder error."));
+ else
+ status = android::binder::Status::ok();
+ }
+ os_free((void *)iface.driver);
+ os_free((void *)iface.ifname);
+ os_free((void *)iface.confname);
+ os_free((void *)iface.bridge_ifname);
+ return status;
+}
+
+android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_UNKNOWN,
+ android::String8("wpa_supplicant does not control this "
+ "interface."));
+ if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8(
+ "wpa_supplicant couldn't remove this interface."));
+ return android::binder::Status::ok();
+}
+
+android::binder::Status Supplicant::GetInterface(
+ const std::string &ifname,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_UNKNOWN,
+ android::String8(
+ "wpa_supplicant does not control this interface."));
+
+ BinderManager *binder_manager = BinderManager::getInstance();
+ if (!binder_manager ||
+ binder_manager->getIfaceBinderObjectByKey(
+ wpa_s->binder_object_key, aidl_return))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8(
+ "wpa_supplicant encountered a binder error."));
+
+ return android::binder::Status::ok();
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h
new file mode 100644
index 0000000..136b99b
--- /dev/null
+++ b/wpa_supplicant/binder/supplicant.h
@@ -0,0 +1,55 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+
+#include "fi/w1/wpa_supplicant/BnSupplicant.h"
+#include "fi/w1/wpa_supplicant/IIface.h"
+#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of the supplicant binder object. This binder
+ * object is used core for global control operations on
+ * wpa_supplicant.
+ */
+class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant
+{
+public:
+ Supplicant(struct wpa_global *global);
+ virtual ~Supplicant() = default;
+
+ android::binder::Status CreateInterface(
+ const android::os::PersistableBundle &params,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+ android::binder::Status
+ RemoveInterface(const std::string &ifname) override;
+ android::binder::Status GetInterface(
+ const std::string &ifname,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+
+private:
+ /* Raw pointer to the global structure maintained by the core. */
+ struct wpa_global *wpa_global_;
+ /* All the callback objects registered by the clients. */
+ std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
+ callbacks_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 1051ee3..3a8778d 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
+#include "eap_peer/eap.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "notify.h"
@@ -60,6 +61,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
anqp = os_zalloc(sizeof(*anqp));
if (anqp == NULL)
return NULL;
+#ifdef CONFIG_INTERWORKING
+ dl_list_init(&anqp->anqp_elems);
+#endif /* CONFIG_INTERWORKING */
anqp->users = 1;
return anqp;
}
@@ -80,6 +84,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
#ifdef CONFIG_INTERWORKING
+ dl_list_init(&n->anqp_elems);
ANQP_DUP(capability_list);
ANQP_DUP(venue_name);
ANQP_DUP(network_auth_type);
@@ -141,6 +146,10 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
*/
static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
{
+#ifdef CONFIG_INTERWORKING
+ struct wpa_bss_anqp_elem *elem;
+#endif /* CONFIG_INTERWORKING */
+
if (anqp == NULL)
return;
@@ -159,6 +168,13 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
wpabuf_free(anqp->nai_realm);
wpabuf_free(anqp->anqp_3gpp);
wpabuf_free(anqp->domain_name);
+
+ while ((elem = dl_list_first(&anqp->anqp_elems,
+ struct wpa_bss_anqp_elem, list))) {
+ dl_list_del(&elem->list);
+ wpabuf_free(elem->payload);
+ os_free(elem);
+ }
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
wpabuf_free(anqp->hs20_capability_list);
@@ -198,8 +214,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
}
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- const char *reason)
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason)
{
if (wpa_s->last_scan_res) {
unsigned int i;
@@ -288,6 +304,47 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
}
+static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+ struct wpa_ssid *ssid;
+ struct wpabuf *wps_ie;
+ int pbc = 0, ret;
+
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ if (!wps_ie)
+ return 0;
+
+ if (wps_is_selected_pbc_registrar(wps_ie)) {
+ pbc = 1;
+ } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+ wpabuf_free(wps_ie);
+ return 0;
+ }
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+ continue;
+ if (ssid->ssid_len &&
+ (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
+ continue;
+
+ if (pbc)
+ ret = eap_is_wps_pbc_enrollee(&ssid->eap);
+ else
+ ret = eap_is_wps_pin_enrollee(&ssid->eap);
+ wpabuf_free(wps_ie);
+ return ret;
+ }
+ wpabuf_free(wps_ie);
+#endif /* CONFIG_WPS */
+
+ return 0;
+}
+
+
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_ssid *ssid;
@@ -326,7 +383,8 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
struct wpa_bss *bss;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- if (!wpa_bss_known(wpa_s, bss)) {
+ if (!wpa_bss_known(wpa_s, bss) &&
+ !wpa_bss_is_wps_candidate(wpa_s, bss)) {
wpa_bss_remove(wpa_s, bss, __func__);
return 0;
}
@@ -784,7 +842,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
struct wpa_bss *bss, *n;
os_get_reltime(&wpa_s->last_scan);
- if (!new_scan)
+ if ((info && info->aborted) || !new_scan)
return; /* do not expire entries without new scan */
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
@@ -1004,20 +1062,7 @@ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
*/
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
- const u8 *end, *pos;
-
- pos = (const u8 *) (bss + 1);
- end = pos + bss->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
+ return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
}
@@ -1037,8 +1082,8 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
pos = (const u8 *) (bss + 1);
end = pos + bss->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1074,8 +1119,8 @@ const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
pos += bss->ie_len;
end = pos + bss->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1110,8 +1155,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
pos = (const u8 *) (bss + 1);
end = pos + bss->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1155,8 +1200,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
pos += bss->ie_len;
end = pos + bss->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index b215380..84e8fb0 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -19,6 +19,12 @@ struct wpa_scan_res;
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+struct wpa_bss_anqp_elem {
+ struct dl_list list;
+ u16 infoid;
+ struct wpabuf *payload;
+};
+
/**
* struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
*/
@@ -34,6 +40,7 @@ struct wpa_bss_anqp {
struct wpabuf *nai_realm;
struct wpabuf *anqp_3gpp;
struct wpabuf *domain_name;
+ struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
struct wpabuf *hs20_capability_list;
@@ -106,6 +113,8 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
struct os_reltime *fetch_time);
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -141,6 +150,17 @@ static inline int bss_is_dmg(const struct wpa_bss *bss)
return bss->freq > 45000;
}
+/**
+ * Test whether a BSS is a PBSS.
+ * This checks whether a BSS is a DMG-band PBSS. PBSS is used for P2P DMG
+ * network.
+ */
+static inline int bss_is_pbss(struct wpa_bss *bss)
+{
+ return bss_is_dmg(bss) &&
+ (bss->caps & IEEE80211_CAP_DMG_MASK) == IEEE80211_CAP_DMG_PBSS;
+}
+
static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
{
if (bss != NULL && new_level < 0)
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b1adab7..dd922ca 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -32,7 +32,11 @@ struct parse_data {
/* Configuration variable name */
char *name;
- /* Parser function for this variable */
+ /* Parser function for this variable. The parser functions return 0 or 1
+ * to indicate success. Value 0 indicates that the parameter value may
+ * have changed while value 1 means that the value did not change.
+ * Error cases (failure to parse the string) are indicated by returning
+ * -1. */
int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
int line, const char *value);
@@ -59,7 +63,7 @@ static int wpa_config_parse_str(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
{
- size_t res_len, *dst_len;
+ size_t res_len, *dst_len, prev_len;
char **dst, *tmp;
if (os_strcmp(value, "NULL") == 0) {
@@ -105,6 +109,21 @@ static int wpa_config_parse_str(const struct parse_data *data,
set:
dst = (char **) (((u8 *) ssid) + (long) data->param1);
dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+ if (data->param2)
+ prev_len = *dst_len;
+ else if (*dst)
+ prev_len = os_strlen(*dst);
+ else
+ prev_len = 0;
+ if ((*dst == NULL && tmp == NULL) ||
+ (*dst && tmp && prev_len == res_len &&
+ os_memcmp(*dst, tmp, res_len) == 0)) {
+ /* No change to the previously configured value */
+ os_free(tmp);
+ return 1;
+ }
+
os_free(*dst);
*dst = tmp;
if (data->param2)
@@ -190,6 +209,9 @@ static int wpa_config_parse_int(const struct parse_data *data,
line, value);
return -1;
}
+
+ if (*dst == val)
+ return 1;
*dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
@@ -456,9 +478,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
+ if (has_ctrl_char((u8 *) value, len)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid passphrase character",
+ line);
+ return -1;
+ }
if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
- os_memcmp(ssid->passphrase, value, len) == 0)
- return 0;
+ os_memcmp(ssid->passphrase, value, len) == 0) {
+ /* No change to the previously configured value */
+ return 1;
+ }
ssid->psk_set = 0;
str_clear_free(ssid->passphrase);
ssid->passphrase = dup_binstr(value, len);
@@ -569,6 +599,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->proto == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
ssid->proto = val;
return errors ? -1 : 0;
@@ -705,6 +737,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->key_mgmt == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
ssid->key_mgmt = val;
return errors ? -1 : 0;
@@ -899,6 +933,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
static int wpa_config_parse_cipher(int line, const char *value)
{
+#ifdef CONFIG_NO_WPA
+ return -1;
+#else /* CONFIG_NO_WPA */
int val = wpa_parse_cipher(value);
if (val < 0) {
wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
@@ -911,12 +948,16 @@ static int wpa_config_parse_cipher(int line, const char *value)
return -1;
}
return val;
+#endif /* CONFIG_NO_WPA */
}
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_cipher(int cipher)
{
+#ifdef CONFIG_NO_WPA
+ return NULL;
+#else /* CONFIG_NO_WPA */
char *buf = os_zalloc(50);
if (buf == NULL)
return NULL;
@@ -927,6 +968,7 @@ static char * wpa_config_write_cipher(int cipher)
}
return buf;
+#endif /* CONFIG_NO_WPA */
}
#endif /* NO_CONFIG_WRITE */
@@ -945,6 +987,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
return -1;
}
+ if (ssid->pairwise_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
ssid->pairwise_cipher = val;
return 0;
@@ -981,6 +1025,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
return -1;
}
+ if (ssid->group_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
ssid->group_cipher = val;
return 0;
@@ -1042,6 +1088,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->auth_alg == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
ssid->auth_alg = val;
return errors ? -1 : 0;
@@ -1296,6 +1344,32 @@ static int wpa_config_parse_eap(const struct parse_data *data,
methods[num_methods].method = EAP_TYPE_NONE;
num_methods++;
+ if (!errors && ssid->eap.eap_methods) {
+ struct eap_method_type *prev_m;
+ size_t i, j, prev_methods, match = 0;
+
+ prev_m = ssid->eap.eap_methods;
+ for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+ prev_m[i].method != EAP_TYPE_NONE; i++) {
+ /* Count the methods */
+ }
+ prev_methods = i + 1;
+
+ for (i = 0; prev_methods == num_methods && i < prev_methods;
+ i++) {
+ for (j = 0; j < num_methods; j++) {
+ if (prev_m[i].vendor == methods[j].vendor &&
+ prev_m[i].method == methods[j].method) {
+ match++;
+ break;
+ }
+ }
+ }
+ if (match == num_methods) {
+ os_free(methods);
+ return 1;
+ }
+ }
wpa_hexdump(MSG_MSGDUMP, "eap methods",
(u8 *) methods, num_methods * sizeof(*methods));
os_free(ssid->eap.eap_methods);
@@ -1348,6 +1422,8 @@ static int wpa_config_parse_password(const struct parse_data *data,
u8 *hash;
if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.password)
+ return 1; /* Already unset */
wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = NULL;
@@ -1411,6 +1487,12 @@ static int wpa_config_parse_password(const struct parse_data *data,
wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+ if (ssid->eap.password && ssid->eap.password_len == 16 &&
+ os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = hash;
ssid->eap.password_len = 16;
@@ -1837,6 +1919,8 @@ static const struct parse_data ssid_fields[] = {
{ FUNC(auth_alg) },
{ FUNC(scan_freq) },
{ FUNC(freq_list) },
+ { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT,
+ VHT_CHANWIDTH_80P80MHZ) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
{ STR_LENe(identity) },
@@ -1910,6 +1994,9 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
{ INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+ { INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
#ifdef CONFIG_MESH
{ FUNC(mesh_basic_rates) },
{ INT(dot11MeshMaxRetries) },
@@ -1918,6 +2005,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
@@ -1967,6 +2055,8 @@ static const struct parse_data ssid_fields[] = {
{ INT(update_identifier) },
#endif /* CONFIG_HS20 */
{ INT_RANGE(mac_addr, 0, 2) },
+ { INT_RANGE(pbss, 0, 2) },
+ { INT_RANGE(wps_disabled, 0, 1) },
};
#undef OFFSET
@@ -2271,6 +2361,11 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->bgscan);
os_free(config->wowlan_triggers);
os_free(config->fst_group_id);
+ os_free(config->sched_scan_plans);
+#ifdef CONFIG_MBO
+ os_free(config->non_pref_chan);
+#endif /* CONFIG_MBO */
+
os_free(config);
}
@@ -2453,7 +2548,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
* @var: Variable name, e.g., "ssid"
* @value: Variable value
* @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
*
* This function can be used to set network configuration variables based on
* both the configuration file and management interface input. The value
@@ -2474,7 +2570,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
if (os_strcmp(var, field->name) != 0)
continue;
- if (field->parser(field, ssid, line, value)) {
+ ret = field->parser(field, ssid, line, value);
+ if (ret < 0) {
if (line) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse %s '%s'.", line, var, value);
@@ -2573,9 +2670,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
return props;
err:
- value = *props;
- while (value)
- os_free(value++);
+ for (i = 0; props[i]; i++)
+ os_free(props[i]);
os_free(props);
return NULL;
#endif /* NO_CONFIG_WRITE */
@@ -2604,8 +2700,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
for (i = 0; i < NUM_SSID_FIELDS; i++) {
const struct parse_data *field = &ssid_fields[i];
- if (os_strcmp(var, field->name) == 0)
- return field->writer(field, ssid);
+ if (os_strcmp(var, field->name) == 0) {
+ char *ret = field->writer(field, ssid);
+
+ if (ret && has_newline(ret)) {
+ wpa_printf(MSG_ERROR,
+ "Found newline in value for %s; not returning it",
+ var);
+ os_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+ }
}
return NULL;
@@ -2790,6 +2897,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
if (os_strcmp(var, "password") == 0 &&
os_strncmp(value, "ext:", 4) == 0) {
+ if (has_newline(value))
+ return -1;
str_clear_free(cred->password);
cred->password = os_strdup(value);
cred->ext_password = 1;
@@ -2840,9 +2949,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
val = wpa_config_parse_string(value, &len);
- if (val == NULL) {
+ if (val == NULL ||
+ (os_strcmp(var, "excluded_ssid") != 0 &&
+ os_strcmp(var, "roaming_consortium") != 0 &&
+ os_strcmp(var, "required_roaming_consortium") != 0 &&
+ has_newline(val))) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
"value '%s'.", line, var, value);
+ os_free(val);
return -1;
}
@@ -3540,6 +3654,11 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
config->cert_in_cb = DEFAULT_CERT_IN_CB;
+ config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+
+#ifdef CONFIG_MBO
+ config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
+#endif /* CONFIG_MBO */
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3646,6 +3765,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
return -1;
}
+ if (has_newline(pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
+ line, data->name);
+ return -1;
+ }
+
tmp = os_strdup(pos);
if (tmp == NULL)
return -1;
@@ -3684,22 +3809,12 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
{
- size_t len;
struct wpabuf **dst, *tmp;
- len = os_strlen(pos);
- if (len & 0x01)
- return -1;
-
- tmp = wpabuf_alloc(len / 2);
- if (tmp == NULL)
+ tmp = wpabuf_parse_bin(pos);
+ if (!tmp)
return -1;
- if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
- wpabuf_free(tmp);
- return -1;
- }
-
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
wpabuf_free(*dst);
*dst = tmp;
@@ -4246,6 +4361,16 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
{ INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
#endif /* CONFIG_FST */
+ { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
+ { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
+#ifdef CONFIG_MBO
+ { STR(non_pref_chan), 0 },
+ { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
+ MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
+#endif /*CONFIG_MBO */
+ { INT(gas_address3), 0 },
+ { INT_RANGE(ftm_responder, 0, 1), 0 },
+ { INT_RANGE(ftm_initiator, 0, 1), 0 },
};
#undef FUNC
@@ -4304,6 +4429,23 @@ int wpa_config_get_value(const char *name, struct wpa_config *config,
}
+int wpa_config_get_num_global_field_names(void)
+{
+ return NUM_GLOBAL_FIELDS;
+}
+
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
+{
+ if (i >= NUM_GLOBAL_FIELDS)
+ return NULL;
+
+ if (no_var)
+ *no_var = !global_fields[i].param1;
+ return global_fields[i].name;
+}
+
+
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
{
size_t i;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 627f38b..48e64be 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -39,6 +39,8 @@
#define DEFAULT_KEY_MGMT_OFFLOAD 1
#define DEFAULT_CERT_IN_CB 1
#define DEFAULT_P2P_GO_CTWINDOW 0
+#define DEFAULT_WPA_RSC_RELAXATION 1
+#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
#include "config_ssid.h"
#include "wps/wps.h"
@@ -331,6 +333,7 @@ struct wpa_cred {
#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
#define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16)
+#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -761,12 +764,17 @@ struct wpa_config {
* frequency list of the local device and the peer device.
*
* @P2P_GO_FREQ_MOVE_STAY: Prefer to stay on the current frequency.
+ *
+ * @P2P_GO_FREQ_MOVE_SCM_ECSA: Same as
+ * P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS but a transition is possible only
+ * if all the group members advertise eCSA support.
*/
enum {
P2P_GO_FREQ_MOVE_SCM = 0,
P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS = 1,
P2P_GO_FREQ_MOVE_STAY = 2,
- P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_STAY,
+ P2P_GO_FREQ_MOVE_SCM_ECSA = 3,
+ P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_SCM_ECSA,
} p2p_go_freq_change_policy;
#define DEFAULT_P2P_GO_FREQ_MOVE P2P_GO_FREQ_MOVE_STAY
@@ -1031,7 +1039,8 @@ struct wpa_config {
*
* By default, PMF is disabled unless enabled by the per-network
* ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
- * this default behavior.
+ * this default behavior for RSN network (this is not applicable for
+ * non-RSN cases).
*/
enum mfp_options pmf;
@@ -1247,6 +1256,78 @@ struct wpa_config {
* interface.
*/
int fst_llt;
+
+ /**
+ * wpa_rsc_relaxation - RSC relaxation on GTK installation
+ *
+ * Values:
+ * 0 - use the EAPOL-Key RSC value on GTK installation
+ * 1 - use the null RSC if a bogus RSC value is detected in message 3
+ * of 4-Way Handshake or message 1 of Group Key Handshake.
+ */
+ int wpa_rsc_relaxation;
+
+ /**
+ * sched_scan_plans - Scan plans for scheduled scan
+ *
+ * Each scan plan specifies the interval between scans and the number of
+ * iterations. The last scan plan only specifies the scan interval and
+ * will be run infinitely.
+ *
+ * format: <interval:iterations> <interval2:iterations2> ... <interval>
+ */
+ char *sched_scan_plans;
+
+#ifdef CONFIG_MBO
+ /**
+ * non_pref_chan - Non-preferred channels list, separated by spaces.
+ *
+ * format: op_class:chan:preference:reason<:detail>
+ * Detail is optional.
+ */
+ char *non_pref_chan;
+
+ /**
+ * mbo_cell_capa - Cellular capabilities for MBO
+ */
+ enum mbo_cellular_capa mbo_cell_capa;
+#endif /* CONFIG_MBO */
+
+ /**
+ * gas_address3 - GAS Address3 field behavior
+ *
+ * Values:
+ * 0 - P2P specification (Address3 = AP BSSID)
+ * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+ * sent to not-associated AP; if associated, AP BSSID)
+ */
+ int gas_address3;
+
+ /**
+ * ftm_responder - Publish FTM (fine timing measurement)
+ * responder functionality
+ *
+ * Values:
+ * 0 - do not publish FTM responder functionality (Default)
+ * 1 - publish FTM responder functionality in
+ * bit 70 of Extended Capabilities element
+ * Note, actual FTM responder operation is managed outside
+ * wpa_supplicant.
+ */
+ int ftm_responder;
+
+ /**
+ * ftm_initiator - Publish FTM (fine timing measurement)
+ * initiator functionality
+ *
+ * Values:
+ * 0 - do not publish FTM initiator functionality (Default)
+ * 1 - publish FTM initiator functionality in
+ * bit 71 of Extended Capabilities element
+ * Note, actual FTM initiator operation is managed outside
+ * wpa_supplicant.
+ */
+ int ftm_initiator;
};
@@ -1305,6 +1386,9 @@ void wpa_config_debug_dump_networks(struct wpa_config *config);
/* Prototypes for common functions from config.c */
int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
+int wpa_config_get_num_global_field_names(void);
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var);
/* Prototypes for backend specific functions from the selected config_*.c */
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index fb438ea..7ae1654 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -747,10 +747,16 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(no_auto_peer);
INT(frequency);
INT(fixed_freq);
+#ifdef CONFIG_ACS
+ INT(acs);
+#endif /* CONFIG_ACS */
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
INT(mixed_cell);
+ INT(max_oper_chwidth);
+ INT(pbss);
+ INT(wps_disabled);
#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
@@ -779,6 +785,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
#endif /* CONFIG_MESH */
INT(wpa_ptk_rekey);
+ INT(group_rekey);
INT(ignore_broadcast_ssid);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
@@ -1136,6 +1143,22 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
fprintf(f, "p2p_go_freq_change_policy=%u\n",
config->p2p_go_freq_change_policy);
+ if (WPA_GET_BE32(config->ip_addr_go))
+ fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
+ config->ip_addr_go[0], config->ip_addr_go[1],
+ config->ip_addr_go[2], config->ip_addr_go[3]);
+ if (WPA_GET_BE32(config->ip_addr_mask))
+ fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n",
+ config->ip_addr_mask[0], config->ip_addr_mask[1],
+ config->ip_addr_mask[2], config->ip_addr_mask[3]);
+ if (WPA_GET_BE32(config->ip_addr_start))
+ fprintf(f, "ip_addr_start=%u.%u.%u.%u\n",
+ config->ip_addr_start[0], config->ip_addr_start[1],
+ config->ip_addr_start[2], config->ip_addr_start[3]);
+ if (WPA_GET_BE32(config->ip_addr_end))
+ fprintf(f, "ip_addr_end=%u.%u.%u.%u\n",
+ config->ip_addr_end[0], config->ip_addr_end[1],
+ config->ip_addr_end[2], config->ip_addr_end[3]);
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
@@ -1299,6 +1322,28 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->wps_priority)
fprintf(f, "wps_priority=%d\n", config->wps_priority);
+
+ if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION)
+ fprintf(f, "wpa_rsc_relaxation=%d\n",
+ config->wpa_rsc_relaxation);
+
+ if (config->sched_scan_plans)
+ fprintf(f, "sched_scan_plans=%s\n", config->sched_scan_plans);
+
+#ifdef CONFIG_MBO
+ if (config->non_pref_chan)
+ fprintf(f, "non_pref_chan=%s\n", config->non_pref_chan);
+ if (config->mbo_cell_capa != DEFAULT_MBO_CELL_CAPA)
+ fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa);
+#endif /* CONFIG_MBO */
+
+ if (config->gas_address3)
+ fprintf(f, "gas_address3=%d\n", config->gas_address3);
+
+ if (config->ftm_responder)
+ fprintf(f, "ftm_responder=%d\n", config->ftm_responder);
+ if (config->ftm_initiator)
+ fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 7ef326c..010b594 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -360,6 +360,19 @@ struct wpa_ssid {
} mode;
/**
+ * pbss - Whether to use PBSS. Relevant to DMG networks only.
+ * 0 = do not use PBSS
+ * 1 = use PBSS
+ * 2 = don't care (not allowed in AP mode)
+ * Used together with mode configuration. When mode is AP, it
+ * means to start a PCP instead of a regular AP. When mode is INFRA it
+ * means connect to a PCP instead of AP. In this mode you can also
+ * specify 2 (don't care) meaning connect to either AP or PCP.
+ * P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in DMG network.
+ */
+ int pbss;
+
+ /**
* disabled - Whether this network is currently disabled
*
* 0 = this network can be used (default).
@@ -431,6 +444,18 @@ struct wpa_ssid {
*/
int fixed_freq;
+#ifdef CONFIG_ACS
+ /**
+ * ACS - Automatic Channel Selection for AP mode
+ *
+ * If present, it will be handled together with frequency.
+ * frequency will be used to determine hardware mode only, when it is
+ * used for both hardware mode and channel when used alone. This will
+ * force the channel to be set to 0, thus enabling ACS.
+ */
+ int acs;
+#endif /* CONFIG_ACS */
+
/**
* mesh_basic_rates - BSS Basic rate set for mesh network
*
@@ -449,6 +474,10 @@ struct wpa_ssid {
int vht;
+ u8 max_oper_chwidth;
+
+ unsigned int vht_center_freq2;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -458,6 +487,14 @@ struct wpa_ssid {
int wpa_ptk_rekey;
/**
+ * group_rekey - Group rekeying time in seconds
+ *
+ * This value, if non-zero, is used as the dot11RSNAConfigGroupRekeyTime
+ * parameter when operating in Authenticator role in IBSS.
+ */
+ int group_rekey;
+
+ /**
* scan_freq - Array of frequencies to scan or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -719,6 +756,14 @@ struct wpa_ssid {
* this MBSS will trigger a peering attempt.
*/
int no_auto_peer;
+
+ /**
+ * wps_disabled - WPS disabled in AP mode
+ *
+ * 0 = WPS enabled and configured (default)
+ * 1 = WPS disabled
+ */
+ int wps_disabled;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 199f04f..82ba3b0 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -933,6 +933,7 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
#ifdef CONFIG_HS20
INT(update_identifier);
#endif /* CONFIG_HS20 */
+ INT(group_rekey);
#undef STR
#undef INT
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 3b97806..d814fdf 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
+#include "utils/module_tests.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -55,6 +56,7 @@
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+ const char *input,
char *buf, int len);
static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
char *val);
@@ -310,6 +312,33 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
}
+static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *lci;
+
+ if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
+ return 0;
+ }
+
+ lci = wpabuf_parse_bin(cmd);
+ if (!lci)
+ return -1;
+
+ if (os_get_reltime(&wpa_s->lci_time)) {
+ wpabuf_free(lci);
+ return -1;
+ }
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = lci;
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -371,6 +400,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wps_corrupt_pkhash = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
wps_corrupt_pkhash);
+ } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
+ if (value[0] == '\0') {
+ wps_force_auth_types_in_use = 0;
+ } else {
+ wps_force_auth_types = strtol(value, NULL, 0);
+ wps_force_auth_types_in_use = 1;
+ }
+ } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
+ if (value[0] == '\0') {
+ wps_force_encr_types_in_use = 0;
+ } else {
+ wps_force_encr_types = strtol(value, NULL, 0);
+ wps_force_encr_types_in_use = 1;
+ }
#endif /* CONFIG_WPS_TESTING */
} else if (os_strcasecmp(cmd, "ampdu") == 0) {
if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
@@ -378,7 +421,6 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
- extern unsigned int tdls_testing;
tdls_testing = strtol(value, NULL, 0);
wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
#endif /* CONFIG_TDLS_TESTING */
@@ -467,6 +509,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->extra_roc_dur = atoi(value);
} else if (os_strcasecmp(cmd, "test_failure") == 0) {
wpa_s->test_failure = atoi(value);
+ } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
+ wpa_s->p2p_go_csa_on_inv = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
+ wpa_s->ignore_auth_resp = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
+ wpa_s->ignore_assoc_disallow = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
+ wpa_s->reject_btm_req_reason = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
@@ -474,6 +524,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_CONFIG_BLOBS */
} else if (os_strcasecmp(cmd, "setband") == 0) {
ret = wpas_ctrl_set_band(wpa_s, value);
+#ifdef CONFIG_MBO
+ } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
+ ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
+ wpas_mbo_update_cell_capa(wpa_s, atoi(value));
+#endif /* CONFIG_MBO */
+ } else if (os_strcasecmp(cmd, "lci") == 0) {
+ ret = wpas_ctrl_iface_set_lci(wpa_s, value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -940,7 +998,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
if (os_strcmp(cmd, "any") == 0)
_bssid = NULL;
else if (os_strcmp(cmd, "get") == 0) {
- ret = wps_generate_pin();
+ if (wps_generate_pin((unsigned int *) &ret) < 0)
+ return -1;
goto done;
} else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
@@ -1833,6 +1892,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
"mode=P2P GO - group "
"formation\n");
break;
+ case WPAS_MODE_MESH:
+ ret = os_snprintf(pos, end - pos,
+ "mode=mesh\n");
+ break;
default:
ret = 0;
break;
@@ -2703,6 +2766,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
return 0;
}
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr) < 0)
+ return -1;
+
+ return wpas_mesh_peer_remove(wpa_s, addr);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_add(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int duration;
+ char *pos;
+
+ pos = os_strstr(cmd, " duration=");
+ if (pos) {
+ *pos = '\0';
+ duration = atoi(pos + 10);
+ } else {
+ duration = -1;
+ }
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ return wpas_mesh_peer_add(wpa_s, addr, duration);
+}
+
#endif /* CONFIG_MESH */
@@ -2832,15 +2929,10 @@ static int wpa_supplicant_ctrl_iface_add_network(
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL)
return -1;
- wpas_notify_network_added(wpa_s, ssid);
-
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
-
ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
if (os_snprintf_error(buflen, ret))
return -1;
@@ -2853,7 +2945,7 @@ static int wpa_supplicant_ctrl_iface_remove_network(
{
int id;
struct wpa_ssid *ssid;
- int was_disabled;
+ int result;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
@@ -2889,54 +2981,17 @@ static int wpa_supplicant_ctrl_iface_remove_network(
id = atoi(cmd);
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid)
- wpas_notify_network_removed(wpa_s, ssid);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
"id=%d", id);
return -1;
}
-
- if (wpa_s->last_ssid == ssid)
- wpa_s->last_ssid = NULL;
-
- if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- /*
- * Invalidate the EAP session cache if the current or
- * previously used network is removed.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- }
-
- if (ssid == wpa_s->current_ssid) {
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-
- if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
- wpa_s->own_disconnect_req = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- }
-
- was_disabled = ssid->disabled;
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
"network id=%d", id);
return -1;
}
-
- if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
- "network from filters");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
return 0;
}
@@ -2945,22 +3000,29 @@ static int wpa_supplicant_ctrl_iface_update_network(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
char *name, char *value)
{
- if (wpa_config_set(ssid, name, value, 0) < 0) {
+ int ret;
+
+ ret = wpa_config_set(ssid, name, value, 0);
+ if (ret < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
"variable '%s'", name);
return -1;
}
+ if (ret == 1)
+ return 0; /* No change to the previously configured value */
if (os_strcmp(name, "bssid") != 0 &&
- os_strcmp(name, "priority") != 0)
+ os_strcmp(name, "priority") != 0) {
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
- /*
- * Invalidate the EAP session cache if anything in the current
- * or previously used configuration changes.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid == ssid ||
+ wpa_s->current_ssid == NULL) {
+ /*
+ * Invalidate the EAP session cache if anything in the
+ * current or previously used configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
}
if ((os_strcmp(name, "psk") == 0 &&
@@ -3935,6 +3997,15 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+ if (os_strcmp(field, "acs") == 0) {
+ res = os_snprintf(buf, buflen, "ACS");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_ACS */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4195,9 +4266,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_P2P_SCAN) {
ie = (const u8 *) (bss + 1);
ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
+ if (ret >= end - pos)
return 0;
- pos += ret;
+ if (ret > 0)
+ pos += ret;
}
#endif /* CONFIG_P2P */
@@ -4231,6 +4303,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_INTERWORKING
if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
struct wpa_bss_anqp *anqp = bss->anqp;
+ struct wpa_bss_anqp_elem *elem;
+
pos = anqp_add_hex(pos, end, "anqp_capability_list",
anqp->capability_list);
pos = anqp_add_hex(pos, end, "anqp_venue_name",
@@ -4260,6 +4334,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
anqp->hs20_osu_providers_list);
#endif /* CONFIG_HS20 */
+
+ dl_list_for_each(elem, &anqp->anqp_elems,
+ struct wpa_bss_anqp_elem, list) {
+ char title[20];
+
+ os_snprintf(title, sizeof(title), "anqp[%u]",
+ elem->infoid);
+ pos = anqp_add_hex(pos, end, title, elem->payload);
+ }
}
#endif /* CONFIG_INTERWORKING */
@@ -4267,9 +4350,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_MESH_SCAN) {
ie = (const u8 *) (bss + 1);
ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
+ if (ret >= end - pos)
return 0;
- pos += ret;
+ if (ret > 0)
+ pos += ret;
}
#endif /* CONFIG_MESH */
@@ -4676,7 +4760,7 @@ static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
return -1;
}
- if (isblank(*last)) {
+ if (isblank((unsigned char) *last)) {
i++;
break;
}
@@ -4848,6 +4932,30 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
}
+static int parse_freq(int chwidth, int freq2)
+{
+ if (freq2 < 0)
+ return -1;
+ if (freq2)
+ return VHT_CHANWIDTH_80P80MHZ;
+
+ switch (chwidth) {
+ case 0:
+ case 20:
+ case 40:
+ return VHT_CHANWIDTH_USE_HT;
+ case 80:
+ return VHT_CHANWIDTH_80MHZ;
+ case 160:
+ return VHT_CHANWIDTH_160MHZ;
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
+ chwidth);
+ return -1;
+ }
+}
+
+
static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
@@ -4864,7 +4972,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int go_intent = -1;
int freq = 0;
int pd;
- int ht40, vht;
+ int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
+ size_t group_ssid_len = 0;
if (!wpa_s->global->p2p_init_wpa_s)
return -1;
@@ -4877,7 +4987,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [auto] */
+ * [ht40] [vht] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -4925,11 +5035,41 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
return -1;
}
+ pos2 = os_strstr(pos, " freq2=");
+ if (pos2)
+ freq2 = atoi(pos2 + 7);
+
+ pos2 = os_strstr(pos, " max_oper_chwidth=");
+ if (pos2)
+ chwidth = atoi(pos2 + 18);
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
+ pos2 = os_strstr(pos, " ssid=");
+ if (pos2) {
+ char *end;
+
+ pos2 += 6;
+ end = os_strchr(pos2, ' ');
+ if (!end)
+ group_ssid_len = os_strlen(pos2) / 2;
+ else
+ group_ssid_len = (end - pos2) / 2;
+ if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
+ hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
+ return -1;
+ group_ssid = _group_ssid;
+ }
+
if (os_strncmp(pos, "pin", 3) == 0) {
/* Request random PIN (to be displayed) and enable the PIN */
wps_method = WPS_PIN_DISPLAY;
} else if (os_strncmp(pos, "pbc", 3) == 0) {
wps_method = WPS_PBC;
+ } else if (os_strstr(pos, "p2ps") != NULL) {
+ wps_method = WPS_P2PS;
} else {
pin = pos;
pos = os_strchr(pin, ' ');
@@ -4938,8 +5078,6 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
*pos++ = '\0';
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (os_strncmp(pos, "p2ps", 4) == 0)
- wps_method = WPS_P2PS;
}
if (!wps_pin_str_valid(pin)) {
os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -4949,8 +5087,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
- auth, go_intent, freq, persistent_id, pd,
- ht40, vht);
+ auth, go_intent, freq, freq2, persistent_id,
+ pd, ht40, vht, max_oper_chwidth,
+ group_ssid, group_ssid_len);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -5505,7 +5644,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40, vht;
+ int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -5543,8 +5682,20 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
- pref_freq);
+ pos = os_strstr(cmd, "freq2=");
+ if (pos)
+ freq2 = atoi(pos + 6);
+
+ pos = os_strstr(cmd, " max_oper_chwidth=");
+ if (pos)
+ chwidth = atoi(pos + 18);
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
+ max_oper_chwidth, pref_freq);
}
@@ -5591,7 +5742,8 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- int id, int freq, int ht40, int vht)
+ int id, int freq, int vht_center_freq2,
+ int ht40, int vht, int vht_chwidth)
{
struct wpa_ssid *ssid;
@@ -5603,8 +5755,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
- NULL, 0, 0);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
+ vht_center_freq2, 0, ht40, vht,
+ vht_chwidth, NULL, 0, 0);
}
@@ -5613,11 +5766,14 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
int freq = 0, persistent = 0, group_id = -1;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
while ((token = str_token(cmd, " ", &context))) {
if (sscanf(token, "freq=%d", &freq) == 1 ||
- sscanf(token, "persistent=%d", &group_id) == 1) {
+ sscanf(token, "freq2=%d", &freq2) == 1 ||
+ sscanf(token, "persistent=%d", &group_id) == 1 ||
+ sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
continue;
} else if (os_strcmp(token, "ht40") == 0) {
ht40 = 1;
@@ -5634,11 +5790,40 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
}
}
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
- freq, ht40, vht);
+ freq, freq2, ht40, vht,
+ max_oper_chwidth);
+
+ return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
+ max_oper_chwidth);
+}
+
+
+static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
+ char *buf, size_t buflen)
+{
+ u8 dev_addr[ETH_ALEN];
+ struct wpa_ssid *ssid;
+ int res;
+ const u8 *iaddr;
+
+ ssid = wpa_s->current_ssid;
+ if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
+ hwaddr_aton(cmd, dev_addr))
+ return -1;
- return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
+ iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
+ if (!iaddr)
+ return -1;
+ res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
}
@@ -5797,8 +5982,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
}
if (os_strcmp(cmd, "listen_channel") == 0) {
- return p2p_set_listen_channel(wpa_s->global->p2p, 81,
- atoi(param), 1);
+ char *pos;
+ u8 channel, op_class;
+
+ channel = atoi(param);
+ pos = os_strchr(param, ' ');
+ op_class = pos ? atoi(pos) : 81;
+
+ return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
+ channel, 1);
}
if (os_strcmp(cmd, "ssid_postfix") == 0) {
@@ -6059,6 +6251,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
return 0;
}
+
+static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int freq = 0, period = 0, interval = 0, count = 0;
+
+ if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
+ {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
+ return -1;
+ }
+
+ return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
+}
+
#endif /* CONFIG_P2P */
@@ -6176,6 +6383,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
u16 id[MAX_ANQP_INFO_ID];
size_t num_id = 0;
u32 subtypes = 0;
+ int get_cell_pref = 0;
used = hwaddr_aton2(dst, dst_addr);
if (used < 0)
@@ -6193,6 +6401,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
#else /* CONFIG_HS20 */
return -1;
#endif /* CONFIG_HS20 */
+ } else if (os_strncmp(pos, "mbo:", 4) == 0) {
+#ifdef CONFIG_MBO
+ int num = atoi(pos + 4);
+ if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
+ return -1;
+ get_cell_pref = 1;
+#else /* CONFIG_MBO */
+ return -1;
+#endif /* CONFIG_MBO */
} else {
id[num_id] = atoi(pos);
if (id[num_id])
@@ -6207,7 +6424,8 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
+ return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ get_cell_pref);
}
@@ -6378,7 +6596,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (subtypes == 0)
return -1;
- return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+ return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
}
@@ -6401,7 +6619,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
ret = hs20_anqp_send_req(wpa_s, addr,
BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
- buf, len);
+ buf, len, 0);
os_free(buf);
@@ -6447,14 +6665,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
ret = hs20_anqp_send_req(wpa_s, dst_addr,
BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
- buf, len);
+ buf, len, 0);
os_free(buf);
return ret;
}
-static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
+static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
+ int buflen)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *ctx = NULL, *icon, *poffset, *psize;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+ cmd += used;
+
+ icon = str_token(cmd, " ", &ctx);
+ poffset = str_token(cmd, " ", &ctx);
+ psize = str_token(cmd, " ", &ctx);
+ if (!icon || !poffset || !psize)
+ return -1;
+
+ wpa_s->fetch_osu_icon_in_progress = 0;
+ return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
+ reply, buflen);
+}
+
+
+static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *icon;
+
+ if (!cmd[0])
+ return hs20_del_icon(wpa_s, NULL, NULL);
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (cmd[used] == ' ')
+ used++;
+ icon = cmd[used] ? &cmd[used] : NULL;
+
+ return hs20_del_icon(wpa_s, dst_addr, icon);
+}
+
+
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
{
u8 dst_addr[ETH_ALEN];
int used;
@@ -6470,7 +6733,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
wpa_s->fetch_osu_icon_in_progress = 0;
return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
- (u8 *) icon, os_strlen(icon));
+ (u8 *) icon, os_strlen(icon), inmem);
}
#endif /* CONFIG_HS20 */
@@ -6560,14 +6823,27 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
{
- int query_reason;
+ int query_reason, list = 0;
query_reason = atoi(cmd);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
- query_reason);
+ cmd = os_strchr(cmd, ' ');
+ if (cmd) {
+ cmd++;
+ if (os_strncmp(cmd, "list", 4) == 0) {
+ list = 1;
+ } else {
+ wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
+ cmd);
+ return -1;
+ }
+ }
- return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
+ query_reason, list ? " candidate list" : "");
+
+ return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list);
}
#endif /* CONFIG_WNM */
@@ -6632,6 +6908,28 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
}
+static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ const char *pos;
+ int threshold = 0;
+ int hysteresis = 0;
+
+ if (wpa_s->bgscan && wpa_s->bgscan_priv) {
+ wpa_printf(MSG_DEBUG,
+ "Reject SIGNAL_MONITOR command - bgscan is active");
+ return -1;
+ }
+ pos = os_strstr(cmd, "THRESHOLD=");
+ if (pos)
+ threshold = atoi(pos + 10);
+ pos = os_strstr(cmd, "HYSTERESIS=");
+ if (pos)
+ hysteresis = atoi(pos + 11);
+ return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
+}
+
+
static int wpas_ctrl_iface_get_pref_freq_list(
struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
{
@@ -6679,6 +6977,34 @@ static int wpas_ctrl_iface_get_pref_freq_list(
}
+static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -6736,13 +7062,13 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
vendor_id = strtoul(cmd, &pos, 16);
- if (!isblank(*pos))
+ if (!isblank((unsigned char) *pos))
return -EINVAL;
subcmd = strtoul(pos, &pos, 10);
if (*pos != '\0') {
- if (!isblank(*pos++))
+ if (!isblank((unsigned char) *pos++))
return -EINVAL;
data_len = os_strlen(pos);
}
@@ -6790,10 +7116,20 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+ wpas_abort_ongoing_scan(wpa_s);
+
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ /*
+ * Avoid possible auto connect re-connection on getting
+ * disconnected due to state flush.
+ */
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ }
+
#ifdef CONFIG_P2P
+ wpas_p2p_group_remove(p2p_wpa_s, "*");
wpas_p2p_cancel(p2p_wpa_s);
p2p_ctrl_flush(p2p_wpa_s);
- wpas_p2p_group_remove(p2p_wpa_s, "*");
wpas_p2p_service_flush(p2p_wpa_s);
p2p_wpa_s->global->p2p_disabled = 0;
p2p_wpa_s->global->p2p_per_sta_psk = 0;
@@ -6803,12 +7139,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
p2p_wpa_s->global->pending_p2ps_group = 0;
+ p2p_wpa_s->global->pending_p2ps_group_freq = 0;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
wps_version_number = 0x20;
wps_testing_dummy_cred = 0;
wps_corrupt_pkhash = 0;
+ wps_force_auth_types_in_use = 0;
+ wps_force_encr_types_in_use = 0;
#endif /* CONFIG_WPS_TESTING */
#ifdef CONFIG_WPS
wpa_s->wps_fragment_size = 0;
@@ -6820,7 +7159,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
- extern unsigned int tdls_testing;
tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
@@ -6866,7 +7204,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->next_ssid = NULL;
#ifdef CONFIG_INTERWORKING
+#ifdef CONFIG_HS20
hs20_cancel_fetch_osu(wpa_s);
+ hs20_del_icon(wpa_s, NULL, NULL);
+#endif /* CONFIG_HS20 */
#endif /* CONFIG_INTERWORKING */
wpa_s->ext_mgmt_frame_handling = 0;
@@ -6874,6 +7215,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->extra_roc_dur = 0;
wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+ wpa_s->p2p_go_csa_on_inv = 0;
+ wpa_s->ignore_auth_resp = 0;
+ wpa_s->ignore_assoc_disallow = 0;
+ wpa_s->reject_btm_req_reason = 0;
+ wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
@@ -6891,6 +7237,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
}
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_SME
+ wpa_s->sme.last_unprot_disconnect.sec = 0;
+#endif /* CONFIG_SME */
}
@@ -6947,6 +7298,13 @@ static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
work, NULL);
+ /*
+ * work->type points to a buffer in ework, so need to replace
+ * that here with a fixed string to avoid use of freed memory
+ * in debug prints.
+ */
+ work->type = "freed-ext-work";
+ work->ctx = NULL;
os_free(ework);
return;
}
@@ -7396,6 +7754,76 @@ static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
}
+static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int freq = 0, datarate = 0, ssi_signal = 0;
+ union wpa_event_data event;
+
+ if (!wpa_s->ext_mgmt_frame_handling)
+ return -1;
+
+ /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "freq=");
+ if (param) {
+ param += 5;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " datarate=");
+ if (param) {
+ param += 10;
+ datarate = atoi(param);
+ }
+
+ param = os_strstr(pos, " ssi_signal=");
+ if (param) {
+ param += 12;
+ ssi_signal = atoi(param);
+ }
+
+ param = os_strstr(pos, " frame=");
+ if (param == NULL)
+ return -1;
+ param += 7;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.freq = freq;
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.datarate = datarate;
+ wpa_s->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
+ wpa_s->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *param;
@@ -7495,7 +7923,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
#define HWSIM_PACKETLEN 1500
#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
-void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
@@ -7529,6 +7958,8 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
char *cmd)
{
int enabled = atoi(cmd);
+ char *pos;
+ const char *ifname;
if (!enabled) {
if (wpa_s->l2_test) {
@@ -7542,7 +7973,13 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
if (wpa_s->l2_test)
return 0;
- wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+ pos = os_strstr(cmd, " ifname=");
+ if (pos)
+ ifname = pos + 8;
+ else
+ ifname = wpa_s->ifname;
+
+ wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
ETHERTYPE_IP, wpas_data_test_rx,
wpa_s, 1);
if (wpa_s->l2_test == NULL)
@@ -7663,8 +8100,6 @@ done:
static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
char *pos;
wpa_trace_fail_after = atoi(cmd);
@@ -7687,9 +8122,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
wpa_trace_fail_func);
#else /* WPA_TRACE_BFD */
@@ -7701,8 +8133,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
char *pos;
wpa_trace_test_fail_after = atoi(cmd);
@@ -7725,9 +8155,6 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
wpa_trace_test_fail_func);
#else /* WPA_TRACE_BFD */
@@ -7735,62 +8162,64 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
#endif /* WPA_TRACE_BFD */
}
-#endif /* CONFIG_TESTING_OPTIONS */
-
-static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
{
- unsigned int i;
- char buf[30];
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i, count = (intptr_t) timeout_ctx;
- wpa_printf(MSG_DEBUG, "Update vendor elements");
+ wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
+ count);
+ for (i = 0; i < count; i++) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
+ i + 1, count);
+ }
+}
- for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
- if (wpa_s->vendor_elem[i]) {
- int res;
- res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
- if (!os_snprintf_error(sizeof(buf), res)) {
- wpa_hexdump_buf(MSG_DEBUG, buf,
- wpa_s->vendor_elem[i]);
- }
- }
- }
+static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int count;
-#ifdef CONFIG_P2P
- if (wpa_s->parent == wpa_s &&
- wpa_s->global->p2p &&
- !wpa_s->global->p2p_disabled)
- p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
-#endif /* CONFIG_P2P */
+ count = atoi(cmd);
+ if (count <= 0)
+ return -1;
+
+ return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
+ (void *) (intptr_t) count);
}
-static struct wpa_supplicant *
-wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
- enum wpa_vendor_elem_frame frame)
+static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
+ const char *cmd)
{
- switch (frame) {
-#ifdef CONFIG_P2P
- case VENDOR_ELEM_PROBE_REQ_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P_GO:
- case VENDOR_ELEM_BEACON_P2P_GO:
- case VENDOR_ELEM_P2P_PD_REQ:
- case VENDOR_ELEM_P2P_PD_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_REQ:
- case VENDOR_ELEM_P2P_GO_NEG_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_CONF:
- case VENDOR_ELEM_P2P_INV_REQ:
- case VENDOR_ELEM_P2P_INV_RESP:
- case VENDOR_ELEM_P2P_ASSOC_REQ:
- return wpa_s->parent;
-#endif /* CONFIG_P2P */
- default:
- return wpa_s;
+ struct wpabuf *buf;
+ size_t len;
+
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ if (len == 0) {
+ buf = NULL;
+ } else {
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
}
+
+ wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
+ return 0;
}
+#endif /* CONFIG_TESTING_OPTIONS */
+
static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
{
@@ -7803,7 +8232,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
@@ -7834,7 +8263,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7845,7 +8274,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7858,7 +8287,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
if (wpa_s->vendor_elem[frame] == NULL)
return 0;
@@ -7876,12 +8305,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
size_t len;
u8 *buf;
struct ieee802_11_elems elems;
- u8 *ie, *end;
+ int res;
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
@@ -7891,7 +8320,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
if (*pos == '*') {
wpabuf_free(wpa_s->vendor_elem[frame]);
wpa_s->vendor_elem[frame] = NULL;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7919,65 +8348,149 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
- ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
- end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
-
- for (; ie + 1 < end; ie += 2 + ie[1]) {
- if (ie + len > end)
- break;
- if (os_memcmp(ie, buf, len) != 0)
- continue;
-
- if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
- wpabuf_free(wpa_s->vendor_elem[frame]);
- wpa_s->vendor_elem[frame] = NULL;
- } else {
- os_memmove(ie, ie + len,
- end - (ie + len));
- wpa_s->vendor_elem[frame]->used -= len;
- }
- os_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
- return 0;
- }
-
+ res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
os_free(buf);
-
- return -1;
+ return res;
}
static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
{
struct wpa_supplicant *wpa_s = ctx;
+ size_t len;
+ const u8 *data;
- if (neighbor_rep) {
- wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
- "length=%u",
- (unsigned int) wpabuf_len(neighbor_rep));
- wpabuf_free(neighbor_rep);
- } else {
+ /*
+ * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
+ * BSSID[6]
+ * BSSID Information[4]
+ * Operating Class[1]
+ * Channel Number[1]
+ * PHY Type[1]
+ * Optional Subelements[variable]
+ */
+#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
+
+ if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+ goto out;
+ }
+
+ data = wpabuf_head_u8(neighbor_rep);
+ len = wpabuf_len(neighbor_rep);
+
+ while (len >= 2 + NR_IE_MIN_LEN) {
+ const u8 *nr;
+ char lci[256 * 2 + 1];
+ char civic[256 * 2 + 1];
+ u8 nr_len = data[1];
+ const u8 *pos = data, *end;
+
+ if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
+ nr_len < NR_IE_MIN_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+ data[0], nr_len);
+ goto out;
+ }
+
+ if (2U + nr_len > len) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+ data[0], len, nr_len);
+ goto out;
+ }
+ pos += 2;
+ end = pos + nr_len;
+
+ nr = pos;
+ pos += NR_IE_MIN_LEN;
+
+ lci[0] = '\0';
+ civic[0] = '\0';
+ while (end - pos > 2) {
+ u8 s_id, s_len;
+
+ s_id = *pos++;
+ s_len = *pos++;
+ if (s_len > end - pos)
+ goto out;
+ if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
+ /* Measurement Token[1] */
+ /* Measurement Report Mode[1] */
+ /* Measurement Type[1] */
+ /* Measurement Report[variable] */
+ switch (pos[2]) {
+ case MEASURE_TYPE_LCI:
+ if (lci[0])
+ break;
+ wpa_snprintf_hex(lci, sizeof(lci),
+ pos, s_len);
+ break;
+ case MEASURE_TYPE_LOCATION_CIVIC:
+ if (civic[0])
+ break;
+ wpa_snprintf_hex(civic, sizeof(civic),
+ pos, s_len);
+ break;
+ }
+ }
+
+ pos += s_len;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+ "bssid=" MACSTR
+ " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
+ MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
+ nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
+ nr[ETH_ALEN + 6],
+ lci[0] ? " lci=" : "", lci,
+ civic[0] ? " civic=" : "", civic);
+
+ data = end;
+ len -= 2 + nr_len;
}
+
+out:
+ wpabuf_free(neighbor_rep);
}
-static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
- char *cmd)
+static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
+ char *cmd)
{
- struct wpa_ssid ssid;
- struct wpa_ssid *ssid_p = NULL;
- int ret = 0;
+ struct wpa_ssid_value ssid, *ssid_p = NULL;
+ int ret, lci = 0, civic = 0;
+ char *ssid_s;
- if (os_strncmp(cmd, " ssid=", 6) == 0) {
- ssid.ssid_len = os_strlen(cmd + 6);
- if (ssid.ssid_len > SSID_MAX_LEN)
+ ssid_s = os_strstr(cmd, "ssid=");
+ if (ssid_s) {
+ if (ssid_parse(ssid_s + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Send Neighbor Report: bad SSID");
return -1;
- ssid.ssid = (u8 *) (cmd + 6);
+ }
+
ssid_p = &ssid;
+
+ /*
+ * Move cmd after the SSID text that may include "lci" or
+ * "civic".
+ */
+ cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
+ if (cmd)
+ cmd++;
+
}
- ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+ if (cmd && os_strstr(cmd, "lci"))
+ lci = 1;
+
+ if (cmd && os_strstr(cmd, "civic"))
+ civic = 1;
+
+ ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
wpas_ctrl_neighbor_rep_cb,
wpa_s);
@@ -8062,10 +8575,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
}
} else if (wpa_s->sched_scanning &&
(type & MAC_ADDR_RAND_SCHED_SCAN)) {
- /* simulate timeout to restart the sched scan */
- wpa_s->sched_scan_timed_out = 1;
- wpa_s->prev_sched_ssid = NULL;
- wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpas_scan_restart_sched_scan(wpa_s);
}
return 0;
}
@@ -8091,12 +8601,8 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
addr, mask);
- if (wpa_s->sched_scanning && !wpa_s->pno) {
- /* simulate timeout to restart the sched scan */
- wpa_s->sched_scan_timed_out = 1;
- wpa_s->prev_sched_ssid = NULL;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- }
+ if (wpa_s->sched_scanning && !wpa_s->pno)
+ wpas_scan_restart_sched_scan(wpa_s);
}
if (type & MAC_ADDR_RAND_PNO) {
@@ -8112,6 +8618,29 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
}
+static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ size_t reply_len;
+
+ reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
+#ifdef CONFIG_AP
+ reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
+ buflen - reply_len);
+#endif /* CONFIG_AP */
+ return reply_len;
+}
+
+
+static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
+{
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+#ifdef CONFIG_AP
+ wpas_ap_pmksa_cache_flush(wpa_s);
+#endif /* CONFIG_AP */
+}
+
+
static int wpas_ctrl_cmd_debug_level(const char *cmd)
{
if (os_strcmp(cmd, "PING") == 0 ||
@@ -8183,10 +8712,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = wpa_supplicant_ctrl_iface_status(
wpa_s, buf + 6, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA") == 0) {
- reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
- reply_size);
+ reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+ wpas_ctrl_iface_pmksa_flush(wpa_s);
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
@@ -8354,6 +8882,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
buf + 18))
reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
+ reply_len = -1;
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
@@ -8388,6 +8922,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
+ reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
+ reply_size);
} else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
reply_len = -1;
@@ -8453,6 +8990,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
+ if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
+ if (wpas_p2p_lo_stop(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -8506,10 +9049,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
- if (hs20_icon_request(wpa_s, buf + 18) < 0)
+ if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
+ if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
+ reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
+ if (del_hs20_icon(wpa_s, buf + 14) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "FETCH_OSU") == 0) {
- if (hs20_fetch_osu(wpa_s) < 0)
+ if (hs20_fetch_osu(wpa_s, 0) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
+ if (hs20_fetch_osu(wpa_s, 1) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
hs20_cancel_fetch_osu(wpa_s);
@@ -8548,16 +9102,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = wpa_supplicant_ctrl_iface_list_networks(
wpa_s, NULL, reply, reply_size);
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- wpa_s->reassociate = 0;
- wpa_s->disconnected = 1;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_cancel_scan(wpa_s);
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpas_request_disconnection(wpa_s);
} else if (os_strcmp(buf, "SCAN") == 0) {
wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
@@ -8565,6 +9110,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
+ if (wpas_abort_ongoing_scan(wpa_s) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
reply_len = -1;
@@ -8623,9 +9171,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
reply_len = wpa_supplicant_global_iface_list(
wpa_s->global, reply, reply_size);
- } else if (os_strcmp(buf, "INTERFACES") == 0) {
+ } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
reply_len = wpa_supplicant_global_iface_interfaces(
- wpa_s->global, reply, reply_size);
+ wpa_s->global, buf + 10, reply, reply_size);
} else if (os_strncmp(buf, "BSS ", 4) == 0) {
reply_len = wpa_supplicant_ctrl_iface_bss(
wpa_s, buf + 4, reply, reply_size);
@@ -8706,6 +9254,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
reply_size);
+ } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
+ if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
+ reply_len = -1;
} else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
reply_size);
@@ -8714,6 +9265,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_AUTOSCAN */
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -8744,6 +9298,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+ } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+ if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -8769,6 +9326,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "GET_FAIL") == 0) {
reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
+ if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
+ if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -8780,7 +9343,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
- if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+ if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
reply_len = -1;
} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
wpas_ctrl_iface_erp_flush(wpa_s);
@@ -8813,10 +9376,11 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
struct wpa_supplicant *wpa_s;
unsigned int create_iface = 0;
u8 mac_addr[ETH_ALEN];
+ enum wpa_driver_if_type type = WPA_IF_STATION;
/*
* <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
- * TAB<bridge_ifname>[TAB<create>]
+ * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
@@ -8884,9 +9448,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
if (!extra[0])
break;
- if (os_strcmp(extra, "create") == 0)
+ if (os_strcmp(extra, "create") == 0) {
create_iface = 1;
- else {
+ if (!pos)
+ break;
+
+ if (os_strcmp(pos, "sta") == 0) {
+ type = WPA_IF_STATION;
+ } else if (os_strcmp(pos, "ap") == 0) {
+ type = WPA_IF_AP_BSS;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "INTERFACE_ADD unsupported interface type: '%s'",
+ pos);
+ return -1;
+ }
+ } else {
wpa_printf(MSG_DEBUG,
"INTERFACE_ADD unsupported extra parameter: '%s'",
extra);
@@ -8899,7 +9476,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
iface.ifname);
if (!global->ifaces)
return -1;
- if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname,
+ if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
NULL, NULL, NULL, mac_addr, NULL) < 0) {
wpa_printf(MSG_ERROR,
"CTRL_IFACE interface creation failed");
@@ -9008,18 +9585,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+ const char *input,
char *buf, int len)
{
int res;
char *pos, *end;
struct wpa_supplicant *wpa_s;
+ int show_ctrl = 0;
+
+ if (input)
+ show_ctrl = !!os_strstr(input, "ctrl");
wpa_s = global->ifaces;
pos = buf;
end = buf + len;
while (wpa_s) {
- res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+ if (show_ctrl)
+ res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
+ wpa_s->ifname,
+ wpa_s->conf->ctrl_interface ?
+ wpa_s->conf->ctrl_interface : "N/A");
+ else
+ res = os_snprintf(pos, end - pos, "%s\n",
+ wpa_s->ifname);
+
if (os_snprintf_error(end - pos, res)) {
*pos = '\0';
break;
@@ -9085,6 +9675,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
"P2P_LISTEN ",
"P2P_GROUP_REMOVE ",
"P2P_GROUP_ADD ",
+ "P2P_GROUP_MEMBER ",
"P2P_PROV_DISC ",
"P2P_SERV_DISC_REQ ",
"P2P_SERV_DISC_CANCEL_REQ ",
@@ -9408,9 +9999,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
reply_len = wpa_supplicant_global_iface_list(
global, reply, reply_size);
- } else if (os_strcmp(buf, "INTERFACES") == 0) {
+ } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
reply_len = wpa_supplicant_global_iface_interfaces(
- global, reply, reply_size);
+ global, buf + 10, reply, reply_size);
#ifdef CONFIG_FST
} else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
@@ -9456,7 +10047,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
reply_size);
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
- int wpas_module_tests(void);
if (wpas_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 76f69f2..0dc0937 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -48,13 +48,33 @@ struct ctrl_iface_priv {
u8 cookie[COOKIE_LEN];
};
+struct ctrl_iface_global_priv {
+ int sock;
+ struct wpa_ctrl_dst *ctrl_dst;
+ u8 cookie[COOKIE_LEN];
+};
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
+ struct wpa_ctrl_dst **head,
int level, const char *buf,
size_t len);
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst)
+{
+ struct wpa_ctrl_dst *prev;
+
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ os_free(prev);
+ }
+}
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 *from,
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -73,8 +93,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
os_memcpy(&dst->addr, from, sizeof(*from));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
- dst->next = priv->ctrl_dst;
- priv->ctrl_dst = dst;
+ dst->next = *head;
+ *head = dst;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
@@ -87,7 +107,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
}
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 *from,
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -100,7 +120,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
char addr[INET6_ADDRSTRLEN];
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
- dst = priv->ctrl_dst;
+ dst = *head;
while (dst) {
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
if (from->sin6_port == dst->addr.sin6_port &&
@@ -118,7 +138,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
ntohs(from->sin_port));
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (prev == NULL)
- priv->ctrl_dst = dst->next;
+ *head = dst->next;
else
prev->next = dst->next;
os_free(dst);
@@ -282,14 +302,16 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
pos++;
if (os_strcmp(pos, "ATTACH") == 0) {
- if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+ &from, fromlen))
reply_len = 1;
else {
new_attached = 1;
reply_len = 2;
}
} else if (os_strcmp(pos, "DETACH") == 0) {
- if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+ if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
+ &from, fromlen))
reply_len = 1;
else
reply_len = 2;
@@ -327,9 +349,28 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
- if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+ if (!wpa_s)
return;
- wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+ if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
+ struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+
+ if (priv->ctrl_dst) {
+ wpa_supplicant_ctrl_iface_send(
+ wpa_s,
+ type != WPA_MSG_PER_INTERFACE ?
+ NULL : wpa_s->ifname,
+ priv->sock, &priv->ctrl_dst, level, txt, len);
+ }
+ }
+
+ if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface)
+ return;
+
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
+ &wpa_s->ctrl_iface->ctrl_dst,
+ level, txt, len);
}
@@ -337,7 +378,9 @@ struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
+ char port_str[40];
int port = WPA_CTRL_IFACE_PORT;
+ char *pos;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 addr;
int domain = PF_INET6;
@@ -356,6 +399,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->ctrl_interface == NULL)
return priv;
+ pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
+ wpa_s->conf->ctrl_interface);
+ goto fail;
+ }
+ }
+
priv->sock = socket(domain, SOCK_DGRAM, 0);
if (priv->sock < 0) {
wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
@@ -392,6 +446,15 @@ try_again:
goto fail;
}
+ /* Update the ctrl_interface value to match the selected port */
+ os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+ os_free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface = os_strdup(port_str);
+ if (!wpa_s->conf->ctrl_interface) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
+ goto fail;
+ }
+
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
@@ -412,8 +475,6 @@ fail:
void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
{
- struct wpa_ctrl_dst *dst, *prev;
-
if (priv->sock > -1) {
eloop_unregister_read_sock(priv->sock);
if (priv->ctrl_dst) {
@@ -430,22 +491,19 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
priv->sock = -1;
}
- dst = priv->ctrl_dst;
- while (dst) {
- prev = dst;
- dst = dst->next;
- os_free(prev);
- }
+ wpas_ctrl_iface_free_dst(priv->ctrl_dst);
os_free(priv);
}
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
+ struct wpa_ctrl_dst **head,
int level, const char *buf,
size_t len)
{
struct wpa_ctrl_dst *dst, *next;
- char levelstr[10];
+ char levelstr[64];
int idx;
char *sbuf;
int llen;
@@ -453,11 +511,15 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
char addr[INET6_ADDRSTRLEN];
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
- dst = priv->ctrl_dst;
- if (priv->sock < 0 || dst == NULL)
+ dst = *head;
+ if (sock < 0 || dst == NULL)
return;
- os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ if (ifname)
+ os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+ ifname, level);
+ else
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
llen = os_strlen(levelstr);
sbuf = os_malloc(llen + len);
@@ -481,7 +543,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
inet_ntoa(dst->addr.sin_addr),
ntohs(dst->addr.sin_port));
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
- if (sendto(priv->sock, sbuf, llen + len, 0,
+ if (sendto(sock, sbuf, llen + len, 0,
(struct sockaddr *) &dst->addr,
sizeof(dst->addr)) < 0) {
wpa_printf(MSG_ERROR,
@@ -490,7 +552,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
dst->errors++;
if (dst->errors > 10) {
wpa_supplicant_ctrl_iface_detach(
- priv, &dst->addr,
+ head, &dst->addr,
dst->addrlen);
}
} else
@@ -513,12 +575,6 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
/* Global ctrl_iface */
-struct ctrl_iface_global_priv {
- int sock;
- u8 cookie[COOKIE_LEN];
-};
-
-
static char *
wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
size_t *reply_len)
@@ -546,9 +602,13 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_global_priv *priv = sock_ctx;
char buf[256], *pos;
int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 from;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
socklen_t fromlen = sizeof(from);
- char *reply;
+ char *reply = NULL;
size_t reply_len;
u8 cookie[COOKIE_LEN];
@@ -561,6 +621,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
}
#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -572,6 +633,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
buf[res] = '\0';
@@ -603,17 +665,34 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
while (*pos == ' ')
pos++;
- reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
- &reply_len);
+ if (os_strcmp(pos, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+ &from, fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else if (os_strcmp(pos, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
+ &from, fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else {
+ reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
+ &reply_len);
+ }
done:
if (reply) {
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen);
os_free(reply);
- } else if (reply_len) {
+ } else if (reply_len == 1) {
sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
fromlen);
+ } else if (reply_len == 2) {
+ sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
+ fromlen);
}
}
@@ -623,6 +702,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
struct ctrl_iface_global_priv *priv;
struct sockaddr_in addr;
+ char *pos;
int port = WPA_GLOBAL_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
@@ -637,6 +717,17 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
wpa_printf(MSG_DEBUG, "Global control interface '%s'",
global->params.ctrl_interface);
+ pos = os_strstr(global->params.ctrl_interface, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
+ global->params.ctrl_interface);
+ goto fail;
+ }
+ }
+
priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (priv->sock < 0) {
wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
@@ -655,7 +746,7 @@ try_again:
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
port++;
if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
- WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+ WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
goto try_again;
wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
@@ -668,6 +759,7 @@ try_again:
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
return priv;
@@ -686,5 +778,7 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
eloop_unregister_read_sock(priv->sock);
close(priv->sock);
}
+
+ wpas_ctrl_iface_free_dst(priv->ctrl_dst);
os_free(priv);
}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 11f2814..4db712f 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -15,7 +15,6 @@
#include <fcntl.h>
#ifdef __linux__
#include <sys/ioctl.h>
-#include <linux/sockios.h>
#endif /* __linux__ */
#ifdef ANDROID
#include <cutils/sockets.h>
@@ -24,6 +23,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/list.h"
+#include "common/ctrl_iface_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "config.h"
#include "wpa_supplicant_i.h"
@@ -31,27 +31,13 @@
/* Per-interface ctrl_iface */
-/**
- * struct wpa_ctrl_dst - Internal data structure of control interface monitors
- *
- * This structure is used to store information about registered control
- * interface monitors into struct wpa_supplicant. This data is private to
- * ctrl_iface_unix.c and should not be touched directly from other files.
- */
-struct wpa_ctrl_dst {
- struct dl_list list;
- struct sockaddr_un addr;
- socklen_t addrlen;
- int debug_level;
- int errors;
-};
-
-
struct ctrl_iface_priv {
struct wpa_supplicant *wpa_s;
int sock;
struct dl_list ctrl_dst;
int android_control_socket;
+ struct dl_list msg_queue;
+ unsigned int throttle_count;
};
@@ -60,6 +46,17 @@ struct ctrl_iface_global_priv {
int sock;
struct dl_list ctrl_dst;
int android_control_socket;
+ struct dl_list msg_queue;
+ unsigned int throttle_count;
+};
+
+struct ctrl_iface_msg {
+ struct dl_list list;
+ struct wpa_supplicant *wpa_s;
+ int level;
+ enum wpa_msg_type type;
+ const char *txt;
+ size_t len;
};
@@ -92,7 +89,7 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
sndbuf = -1;
- if (ioctl(sock, SIOCOUTQ, &outq) < 0)
+ if (ioctl(sock, TIOCOUTQ, &outq) < 0)
outq = -1;
wpa_printf(level,
@@ -103,81 +100,29 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen, int global)
{
- struct wpa_ctrl_dst *dst;
- char addr_txt[200];
-
- dst = os_zalloc(sizeof(*dst));
- if (dst == NULL)
- return -1;
- os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
- dst->addrlen = fromlen;
- dst->debug_level = MSG_INFO;
- dl_list_add(ctrl_dst, &dst->list);
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
- global ? "global " : "", addr_txt);
- return 0;
+ return ctrl_iface_attach(ctrl_dst, from, fromlen);
}
static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
- struct wpa_ctrl_dst *dst;
-
- dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- char addr_txt[200];
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s",
- addr_txt);
- dl_list_del(&dst->list);
- os_free(dst);
- return 0;
- }
- }
- return -1;
+ return ctrl_iface_detach(ctrl_dst, from, fromlen);
}
static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen,
char *level)
{
- struct wpa_ctrl_dst *dst;
-
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
- dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- char addr_txt[200];
- dst->debug_level = atoi(level);
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) from->sun_path, fromlen -
- offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s",
- dst->debug_level, addr_txt);
- return 0;
- }
- }
-
- return -1;
+ return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level);
}
@@ -188,7 +133,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_priv *priv = sock_ctx;
char buf[4096];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len = 0;
@@ -334,33 +279,209 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
}
+static int wpas_ctrl_iface_throttle(int sock)
+{
+#ifdef __linux__
+ socklen_t optlen;
+ int sndbuf, outq;
+
+ optlen = sizeof(sndbuf);
+ sndbuf = 0;
+ if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 ||
+ ioctl(sock, TIOCOUTQ, &outq) < 0 ||
+ sndbuf <= 0 || outq < 0)
+ return 0;
+ return outq > sndbuf / 2;
+#else /* __linux__ */
+ return 0;
+#endif /* __linux__ */
+}
+
+
+static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *gpriv;
+ struct ctrl_iface_msg *msg;
+
+ gpriv = global->ctrl_iface;
+ while (gpriv && !dl_list_empty(&gpriv->msg_queue) &&
+ !wpas_ctrl_iface_throttle(gpriv->sock)) {
+ msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg,
+ list);
+ if (!msg)
+ break;
+ dl_list_del(&msg->list);
+ wpa_supplicant_ctrl_iface_send(
+ msg->wpa_s,
+ msg->type != WPA_MSG_PER_INTERFACE ?
+ NULL : msg->wpa_s->ifname,
+ gpriv->sock, &gpriv->ctrl_dst, msg->level,
+ msg->txt, msg->len, NULL, gpriv);
+ os_free(msg);
+ }
+}
+
+
+static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+ struct ctrl_iface_msg *msg;
+
+ priv = wpa_s->ctrl_iface;
+ while (priv && !dl_list_empty(&priv->msg_queue) &&
+ !wpas_ctrl_iface_throttle(priv->sock)) {
+ msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg,
+ list);
+ if (!msg)
+ break;
+ dl_list_del(&msg->list);
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
+ &priv->ctrl_dst, msg->level,
+ msg->txt, msg->len, priv, NULL);
+ os_free(msg);
+ }
+}
+
+
+static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct ctrl_iface_priv *priv;
+ struct ctrl_iface_global_priv *gpriv;
+ int sock = -1, gsock = -1;
+
+ wpas_ctrl_msg_send_pending_global(wpa_s->global);
+ wpas_ctrl_msg_send_pending_iface(wpa_s);
+
+ priv = wpa_s->ctrl_iface;
+ if (priv && !dl_list_empty(&priv->msg_queue))
+ sock = priv->sock;
+
+ gpriv = wpa_s->global->ctrl_iface;
+ if (gpriv && !dl_list_empty(&gpriv->msg_queue))
+ gsock = gpriv->sock;
+
+ if (sock > -1 || gsock > -1) {
+ /* Continue pending message transmission from a timeout */
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)",
+ sock, gsock);
+ eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout,
+ wpa_s, NULL);
+ }
+}
+
+
+static void wpas_ctrl_msg_queue(struct dl_list *queue,
+ struct wpa_supplicant *wpa_s, int level,
+ enum wpa_msg_type type,
+ const char *txt, size_t len)
+{
+ struct ctrl_iface_msg *msg;
+
+ msg = os_zalloc(sizeof(*msg) + len);
+ if (!msg)
+ return;
+
+ msg->wpa_s = wpa_s;
+ msg->level = level;
+ msg->type = type;
+ os_memcpy(msg + 1, txt, len);
+ msg->txt = (const char *) (msg + 1);
+ msg->len = len;
+ dl_list_add_tail(queue, &msg->list);
+ eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+ eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+}
+
+
+static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count,
+ struct dl_list *queue)
+{
+ struct ctrl_iface_msg *msg;
+
+ if (throttle_count < 2000)
+ return;
+
+ msg = dl_list_first(queue, struct ctrl_iface_msg, list);
+ if (msg) {
+ wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message");
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+}
+
+
static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
enum wpa_msg_type type,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct ctrl_iface_priv *priv;
+ struct ctrl_iface_global_priv *gpriv;
if (wpa_s == NULL)
return;
- if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
- struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
- if (!dl_list_empty(&priv->ctrl_dst)) {
+ gpriv = wpa_s->global->ctrl_iface;
+
+ if (type != WPA_MSG_NO_GLOBAL && gpriv &&
+ !dl_list_empty(&gpriv->ctrl_dst)) {
+ if (!dl_list_empty(&gpriv->msg_queue) ||
+ wpas_ctrl_iface_throttle(gpriv->sock)) {
+ if (gpriv->throttle_count == 0) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle global event message for sock %d",
+ gpriv->sock);
+ }
+ gpriv->throttle_count++;
+ wpas_ctrl_msg_queue_limit(gpriv->throttle_count,
+ &gpriv->msg_queue);
+ wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level,
+ type, txt, len);
+ } else {
+ if (gpriv->throttle_count) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle %u global event message(s) for sock %d",
+ gpriv->throttle_count, gpriv->sock);
+ }
+ gpriv->throttle_count = 0;
wpa_supplicant_ctrl_iface_send(
wpa_s,
type != WPA_MSG_PER_INTERFACE ?
NULL : wpa_s->ifname,
- priv->sock, &priv->ctrl_dst, level, txt, len,
- NULL, priv);
+ gpriv->sock, &gpriv->ctrl_dst, level,
+ txt, len, NULL, gpriv);
}
}
- if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL)
- return;
- wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
- &wpa_s->ctrl_iface->ctrl_dst,
- level, txt, len, wpa_s->ctrl_iface,
- NULL);
+ priv = wpa_s->ctrl_iface;
+
+ if (type != WPA_MSG_ONLY_GLOBAL && priv) {
+ if (!dl_list_empty(&priv->msg_queue) ||
+ wpas_ctrl_iface_throttle(priv->sock)) {
+ if (priv->throttle_count == 0) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle event message for sock %d",
+ priv->sock);
+ }
+ priv->throttle_count++;
+ wpas_ctrl_msg_queue_limit(priv->throttle_count,
+ &priv->msg_queue);
+ wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level,
+ type, txt, len);
+ } else {
+ if (priv->throttle_count) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle %u event message(s) for sock %d",
+ priv->throttle_count, priv->sock);
+ }
+ priv->throttle_count = 0;
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
+ &priv->ctrl_dst, level,
+ txt, len, priv, NULL);
+ }
+ }
}
@@ -578,6 +699,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
if (priv == NULL)
return NULL;
dl_list_init(&priv->ctrl_dst);
+ dl_list_init(&priv->msg_queue);
priv->wpa_s = wpa_s;
priv->sock = -1;
@@ -671,6 +793,8 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
{
struct wpa_ctrl_dst *dst, *prev;
+ struct ctrl_iface_msg *msg, *prev_msg;
+ struct ctrl_iface_global_priv *gpriv;
if (priv->sock > -1) {
char *fname;
@@ -724,8 +848,26 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
free_dst:
dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
- list)
+ list) {
+ dl_list_del(&dst->list);
os_free(dst);
+ }
+ dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+ gpriv = priv->wpa_s->global->ctrl_iface;
+ if (gpriv) {
+ dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ if (msg->wpa_s == priv->wpa_s) {
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+ }
+ }
+ eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL);
os_free(priv);
}
@@ -785,33 +927,31 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
int _errno;
- char addr_txt[200];
+ char txt[200];
if (level < dst->debug_level)
continue;
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) dst->addr.sun_path, dst->addrlen -
- offsetof(struct sockaddr_un, sun_path));
msg.msg_name = (void *) &dst->addr;
msg.msg_namelen = dst->addrlen;
wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len);
if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
- wpa_printf(MSG_MSGDUMP,
- "CTRL_IFACE monitor sent successfully to %s",
- addr_txt);
+ sockaddr_print(MSG_MSGDUMP,
+ "CTRL_IFACE monitor sent successfully to",
+ &dst->addr, dst->addrlen);
dst->errors = 0;
continue;
}
_errno = errno;
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
- addr_txt, errno, strerror(errno));
+ os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for",
+ _errno, strerror(_errno));
+ sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen);
dst->errors++;
if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
- wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages",
- addr_txt);
+ sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:",
+ &dst->addr, dst->addrlen);
wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
dst->addrlen);
}
@@ -845,9 +985,12 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
{
char buf[256];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
+ if (priv->sock == -1)
+ return;
+
for (;;) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
"attach", priv->wpa_s->ifname);
@@ -905,7 +1048,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_global_priv *priv = sock_ctx;
char buf[4096];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
@@ -1155,6 +1298,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
if (priv == NULL)
return NULL;
dl_list_init(&priv->ctrl_dst);
+ dl_list_init(&priv->msg_queue);
priv->global = global;
priv->sock = -1;
@@ -1204,6 +1348,7 @@ void
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
struct wpa_ctrl_dst *dst, *prev;
+ struct ctrl_iface_msg *msg, *prev_msg;
if (priv->sock >= 0) {
eloop_unregister_read_sock(priv->sock);
@@ -1212,7 +1357,14 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
if (priv->global->params.ctrl_interface)
unlink(priv->global->params.ctrl_interface);
dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
- list)
+ list) {
+ dl_list_del(&dst->list);
os_free(dst);
+ }
+ dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
os_free(priv);
}
diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
index c091234..382dcb3 100644
--- a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
+++ b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
@@ -17,11 +17,9 @@
<policy context="default">
<deny own="fi.epitest.hostap.WPASupplicant"/>
<deny send_destination="fi.epitest.hostap.WPASupplicant"/>
- <deny send_interface="fi.epitest.hostap.WPASupplicant"/>
<deny own="fi.w1.wpa_supplicant1"/>
<deny send_destination="fi.w1.wpa_supplicant1"/>
- <deny send_interface="fi.w1.wpa_supplicant1"/>
<deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
</policy>
</busconfig>
diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/wpa_supplicant/dbus/dbus_common_i.h
index a551ccd..95eb4bc 100644
--- a/wpa_supplicant/dbus/dbus_common_i.h
+++ b/wpa_supplicant/dbus/dbus_common_i.h
@@ -13,6 +13,8 @@
#include <dbus/dbus.h>
+struct wpa_dbus_property_desc;
+
struct wpas_dbus_priv {
DBusConnection *con;
int should_dispatch;
@@ -20,9 +22,13 @@ struct wpas_dbus_priv {
u32 next_objid;
int dbus_new_initialized;
-#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+ struct wpa_dbus_property_desc *all_interface_properties;
+ int globals_start;
+#if defined(CONFIG_AP)
int dbus_noc_refcnt;
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
+#endif /* CONFIG_AP */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
};
#endif /* DBUS_COMMON_I_H */
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index a0c44eb..e4e9b8d 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -205,24 +205,6 @@ dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
/**
- * Add a byte entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The byte value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
- const char *key, const char value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
- &value);
-}
-
-
-/**
* Add a boolean entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
@@ -317,62 +299,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
/**
- * Add a 64-bit integer entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The 64-bit integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_int64_t value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
- &value);
-}
-
-
-/**
- * Add a 64-bit unsigned integer entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The 64-bit unsigned integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_uint64_t value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
- &value);
-}
-
-
-/**
- * Add a double-precision floating point entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The double-precision floating point value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
- const char *key, const double value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
- &value);
-}
-
-
-/**
* Add a DBus object path entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index b068431..94a0efd 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -26,9 +26,6 @@ const char * wpa_dbus_type_as_string(const int type);
dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
const char *key, const char *value);
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
- const char *key, const char value);
-
dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
const char *key,
const dbus_bool_t value);
@@ -49,18 +46,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
const char *key,
const dbus_uint32_t value);
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_int64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_uint64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
- const char *key,
- const double value);
-
dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
const char *key,
const char *value);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 67d0e28..27b3012 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1207,7 +1207,7 @@ static int match_group_where_peer_is_client(struct p2p_group *group,
cfg->ssid_len);
if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
wpas_dbus_signal_peer_groups_changed(
- data->wpa_s->parent, data->info->p2p_device_addr);
+ data->wpa_s->p2pdev, data->info->p2p_device_addr);
return 0;
}
@@ -1224,7 +1224,7 @@ static void signal_peer_groups_changed(struct p2p_peer_info *info,
wpa_s_go = wpas_get_p2p_client_iface(data->wpa_s,
info->p2p_device_addr);
if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
- wpas_dbus_signal_peer_groups_changed(data->wpa_s->parent,
+ wpas_dbus_signal_peer_groups_changed(data->wpa_s->p2pdev,
info->p2p_device_addr);
return;
}
@@ -1254,14 +1254,11 @@ static void peer_groups_changed(struct wpa_supplicant *wpa_s)
* irrespective of the role (client/GO) of the current device
*
* @wpa_s: %wpa_supplicant network interface data
- * @ssid: SSID object
* @client: this device is P2P client
- * @network_id: network id of the group started, use instead of ssid->id
- * to account for persistent groups
+ * @persistent: 0 - non persistent group, 1 - persistent group
*/
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id)
+ int client, int persistent)
{
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
@@ -1300,6 +1297,7 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
wpa_s->dbus_new_path) ||
!wpa_dbus_dict_append_string(&dict_iter, "role",
client ? "client" : "GO") ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
wpa_s->dbus_groupobj_path) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
@@ -1950,6 +1948,7 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
}
dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
}
@@ -2000,6 +1999,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
prop = "DisconnectReason";
flush = TRUE;
break;
+ case WPAS_DBUS_PROP_ASSOC_STATUS_CODE:
+ prop = "AssocStatusCode";
+ flush = TRUE;
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -2172,41 +2175,54 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
END_ARGS
}
},
+ { "ExpectDisconnect", WPAS_DBUS_NEW_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_expect_disconnect,
+ {
+ END_ARGS
+ }
+ },
{ NULL, NULL, NULL, { END_ARGS } }
};
static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
wpas_dbus_getter_debug_level,
- wpas_dbus_setter_debug_level
+ wpas_dbus_setter_debug_level,
+ NULL
},
{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
wpas_dbus_getter_debug_timestamp,
- wpas_dbus_setter_debug_timestamp
+ wpas_dbus_setter_debug_timestamp,
+ NULL
},
{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
wpas_dbus_getter_debug_show_keys,
- wpas_dbus_setter_debug_show_keys
+ wpas_dbus_setter_debug_show_keys,
+ NULL
},
{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
wpas_dbus_getter_interfaces,
+ NULL,
NULL
},
{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
wpas_dbus_getter_eap_methods,
+ NULL,
NULL
},
{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
wpas_dbus_getter_global_capabilities,
+ NULL,
NULL
},
#ifdef CONFIG_WIFI_DISPLAY
{ "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
wpas_dbus_getter_global_wfd_ies,
- wpas_dbus_setter_global_wfd_ies
+ wpas_dbus_setter_global_wfd_ies,
+ NULL
},
#endif /* CONFIG_WIFI_DISPLAY */
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
@@ -2234,12 +2250,50 @@ static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
};
+static char * uscore_to_dbus(const char *uscore)
+{
+ const char *p = uscore;
+ char *str, *s;
+ dbus_bool_t last_was_uscore = TRUE;
+
+ s = str = os_zalloc(os_strlen(uscore) + 1);
+ if (!str)
+ return NULL;
+ while (p && *p) {
+ if (*p == '_') {
+ last_was_uscore = TRUE;
+ } else {
+ *s++ = last_was_uscore ? toupper(*p) : *p;
+ last_was_uscore = FALSE;
+ }
+ p++;
+ }
+
+ return str;
+}
+
+
+static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv);
+
+
+static void wpa_dbus_ctrl_iface_props_deinit(struct wpas_dbus_priv *priv)
+{
+ int idx = priv->globals_start;
+
+ /* Free all allocated property values */
+ while (priv->all_interface_properties[idx].dbus_property)
+ os_free((char *)
+ priv->all_interface_properties[idx++].dbus_property);
+ os_free((char *) priv->all_interface_properties);
+}
+
+
/**
* wpas_dbus_ctrl_iface_init - Initialize dbus control interface
* @global: Pointer to global data from wpa_supplicant_init()
* Returns: 0 on success or -1 on failure
*
- * Initialize the dbus control interface for wpa_supplicantand and start
+ * Initialize the dbus control interface for wpa_supplicant and start
* receiving commands from external programs over the bus.
*/
int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
@@ -2247,11 +2301,18 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
struct wpa_dbus_object_desc *obj_desc;
int ret;
+ ret = wpa_dbus_ctrl_iface_props_init(priv);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to init interface properties");
+ return -1;
+ }
+
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
wpa_printf(MSG_ERROR,
"Not enough memory to create object description");
- return -1;
+ goto error;
}
wpas_dbus_register(obj_desc, priv->global, NULL,
@@ -2264,31 +2325,36 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
WPAS_DBUS_NEW_SERVICE,
obj_desc);
- if (ret < 0)
+ if (ret < 0) {
free_dbus_object_desc(obj_desc);
- else
- priv->dbus_new_initialized = 1;
+ goto error;
+ }
- return ret;
+ priv->dbus_new_initialized = 1;
+ return 0;
+
+error:
+ wpa_dbus_ctrl_iface_props_deinit(priv);
+ return -1;
}
/**
* wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
* wpa_supplicant
- * @iface: Pointer to dbus private data from wpas_dbus_init()
+ * @priv: Pointer to dbus private data from wpas_dbus_init()
*
* Deinitialize the dbus control interface that was initialized with
* wpas_dbus_ctrl_iface_init().
*/
-void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
+void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *priv)
{
- if (!iface->dbus_new_initialized)
+ if (!priv->dbus_new_initialized)
return;
wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
WPAS_DBUS_NEW_PATH);
- dbus_connection_unregister_object_path(iface->con,
- WPAS_DBUS_NEW_PATH);
+ dbus_connection_unregister_object_path(priv->con, WPAS_DBUS_NEW_PATH);
+ wpa_dbus_ctrl_iface_props_deinit(priv);
}
@@ -2301,13 +2367,15 @@ static void wpa_dbus_free(void *ptr)
static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
wpas_dbus_getter_network_properties,
- wpas_dbus_setter_network_properties
+ wpas_dbus_setter_network_properties,
+ NULL
},
{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
wpas_dbus_getter_enabled,
- wpas_dbus_setter_enabled
+ wpas_dbus_setter_enabled,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2446,53 +2514,65 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_ssid,
+ NULL,
NULL
},
{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_bssid,
+ NULL,
NULL
},
{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
wpas_dbus_getter_bss_privacy,
+ NULL,
NULL
},
{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
wpas_dbus_getter_bss_mode,
+ NULL,
NULL
},
{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
wpas_dbus_getter_bss_signal,
+ NULL,
NULL
},
{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
wpas_dbus_getter_bss_frequency,
+ NULL,
NULL
},
{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
wpas_dbus_getter_bss_rates,
+ NULL,
NULL
},
{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
wpas_dbus_getter_bss_wpa,
+ NULL,
NULL
},
{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
wpas_dbus_getter_bss_rsn,
+ NULL,
NULL
},
{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
wpas_dbus_getter_bss_wps,
+ NULL,
NULL
},
{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_ies,
+ NULL,
NULL
},
{ "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
wpas_dbus_getter_bss_age,
+ NULL,
NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2992,131 +3072,202 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
#endif /* CONFIG_TDLS */
+ { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_IN },
+ END_ARGS
+ }
+ },
+#ifndef CONFIG_NO_CONFIG_WRITE
+ { "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_save_config,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_NO_CONFIG_WRITE */
{ NULL, NULL, NULL, { END_ARGS } }
};
static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
wpas_dbus_getter_capabilities,
+ NULL,
NULL
},
{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_state,
+ NULL,
NULL
},
{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
wpas_dbus_getter_scanning,
+ NULL,
NULL
},
{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_ap_scan,
- wpas_dbus_setter_ap_scan
+ wpas_dbus_setter_ap_scan,
+ NULL
},
{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_bss_expire_age,
- wpas_dbus_setter_bss_expire_age
+ wpas_dbus_setter_bss_expire_age,
+ NULL
},
{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_bss_expire_count,
- wpas_dbus_setter_bss_expire_count
+ wpas_dbus_setter_bss_expire_count,
+ NULL
},
{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_country,
- wpas_dbus_setter_country
+ wpas_dbus_setter_country,
+ NULL
},
{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_ifname,
+ NULL,
NULL
},
{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_driver,
+ NULL,
NULL
},
{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_bridge_ifname,
+ NULL,
+ NULL
+ },
+ { "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_config_file,
+ NULL,
NULL
},
{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
wpas_dbus_getter_current_bss,
+ NULL,
NULL
},
{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
wpas_dbus_getter_current_network,
+ NULL,
NULL
},
{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_current_auth_mode,
+ NULL,
NULL
},
{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
wpas_dbus_getter_blobs,
+ NULL,
NULL
},
{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
wpas_dbus_getter_bsss,
+ NULL,
NULL
},
{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
wpas_dbus_getter_networks,
+ NULL,
NULL
},
{ "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
wpas_dbus_getter_fast_reauth,
- wpas_dbus_setter_fast_reauth
+ wpas_dbus_setter_fast_reauth,
+ NULL
},
{ "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
wpas_dbus_getter_scan_interval,
- wpas_dbus_setter_scan_interval
+ wpas_dbus_setter_scan_interval,
+ NULL
},
{ "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_pkcs11_engine_path,
+ NULL,
NULL
},
{ "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_pkcs11_module_path,
+ NULL,
NULL
},
#ifdef CONFIG_WPS
{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
wpas_dbus_getter_process_credentials,
- wpas_dbus_setter_process_credentials
+ wpas_dbus_setter_process_credentials,
+ NULL
},
{ "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s",
wpas_dbus_getter_config_methods,
- wpas_dbus_setter_config_methods
+ wpas_dbus_setter_config_methods,
+ NULL
},
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
wpas_dbus_getter_p2p_device_config,
- wpas_dbus_setter_p2p_device_config
+ wpas_dbus_setter_p2p_device_config,
+ NULL
},
{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
wpas_dbus_getter_p2p_peers,
+ NULL,
NULL
},
{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
wpas_dbus_getter_p2p_role,
+ NULL,
NULL
},
{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
wpas_dbus_getter_p2p_group,
+ NULL,
NULL
},
{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
wpas_dbus_getter_p2p_peergo,
+ NULL,
NULL
},
{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
wpas_dbus_getter_persistent_groups,
+ NULL,
NULL
},
#endif /* CONFIG_P2P */
{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
wpas_dbus_getter_disconnect_reason,
+ NULL,
+ NULL
+ },
+ { "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_assoc_status_code,
+ NULL,
NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
@@ -3206,6 +3357,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+ { "DeviceFoundProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
{ "path", "o", ARG_OUT },
@@ -3390,6 +3548,77 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
};
+static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv)
+{
+ size_t all_size;
+ unsigned int i, j, count, num_const, num_globals;
+ const char *global_name;
+ static const char * const ignored_globals[] = {
+ "bss_expiration_age", "bss_expiration_scan_count",
+ "ap_scan", "country", "fast_reauth",
+ "pkcs11_engine_path", "pkcs11_module_path"
+ };
+
+ /* wpas_dbus_interface_properties terminates with a NULL element */
+ num_const = ARRAY_SIZE(wpas_dbus_interface_properties) - 1;
+
+ num_globals = wpa_config_get_num_global_field_names();
+ priv->globals_start = num_const;
+
+ /* allocate enough for all properties + terminating NULL element */
+ all_size = (num_globals + num_const + 1) *
+ sizeof(wpas_dbus_interface_properties[0]);
+ priv->all_interface_properties = os_zalloc(all_size);
+ if (!priv->all_interface_properties) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory for interface properties");
+ return -1;
+ }
+
+ /* Copy constant interface properties to the start of the array */
+ os_memcpy(priv->all_interface_properties,
+ wpas_dbus_interface_properties,
+ sizeof(wpas_dbus_interface_properties));
+
+ /* Dynamically construct interface global properties */
+ for (i = 0, count = num_const; i < num_globals; i++) {
+ struct wpa_dbus_property_desc *desc;
+ int no_var = 0;
+
+ /* ignore globals that are actually just methods */
+ global_name = wpa_config_get_global_field_name(i, &no_var);
+ if (no_var)
+ continue;
+ /* Ignore fields already explicitly exposed */
+ for (j = 0; j < ARRAY_SIZE(ignored_globals); j++) {
+ if (os_strcmp(global_name, ignored_globals[j]) == 0)
+ break;
+ }
+ if (j < ARRAY_SIZE(ignored_globals))
+ continue;
+
+ desc = &priv->all_interface_properties[count++];
+ desc->dbus_property = uscore_to_dbus(global_name);
+ if (!desc->dbus_property) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory for D-Bus property name");
+ goto error;
+ }
+ desc->dbus_interface = WPAS_DBUS_NEW_IFACE_INTERFACE;
+ desc->type = "s";
+ desc->getter = wpas_dbus_getter_iface_global;
+ desc->setter = wpas_dbus_setter_iface_global;
+ desc->data = global_name;
+ }
+
+ return 0;
+
+error:
+ wpa_dbus_ctrl_iface_props_deinit(priv);
+ return -1;
+}
+
+
/**
* wpas_dbus_register_interface - Register an interface with D-Bus
* @wpa_s: wpa_supplicant interface structure
@@ -3397,7 +3626,6 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
*/
int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
{
-
struct wpa_dbus_object_desc *obj_desc = NULL;
struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
int next;
@@ -3423,7 +3651,7 @@ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
}
wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
- wpas_dbus_interface_properties,
+ ctrl_iface->all_interface_properties,
wpas_dbus_interface_signals);
wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
@@ -3489,65 +3717,80 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
{ "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_device_name,
+ NULL,
NULL
},
{ "Manufacturer", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_manufacturer,
+ NULL,
NULL
},
{ "ModelName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_modelname,
+ NULL,
NULL
},
{ "ModelNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_modelnumber,
+ NULL,
NULL
},
{ "SerialNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_serialnumber,
+ NULL,
NULL
},
{ "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
wpas_dbus_getter_p2p_peer_primary_device_type,
+ NULL,
NULL
},
{ "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
wpas_dbus_getter_p2p_peer_config_method,
+ NULL,
NULL
},
{ "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
wpas_dbus_getter_p2p_peer_level,
+ NULL,
NULL
},
{ "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
wpas_dbus_getter_p2p_peer_device_capability,
+ NULL,
NULL
},
{ "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
wpas_dbus_getter_p2p_peer_group_capability,
+ NULL,
NULL
},
{ "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
wpas_dbus_getter_p2p_peer_secondary_device_types,
+ NULL,
NULL
},
{ "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
wpas_dbus_getter_p2p_peer_vendor_extension,
+ NULL,
NULL
},
{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
wpas_dbus_getter_p2p_peer_ies,
+ NULL,
NULL
},
{ "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
wpas_dbus_getter_p2p_peer_device_address,
+ NULL,
NULL
},
{ "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao",
wpas_dbus_getter_p2p_peer_groups,
+ NULL,
NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
@@ -3569,12 +3812,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
* In case of peer objects, it would be emitted by either
* the "interface object" or by "peer objects"
* @sig_name: signal name - DeviceFound
+ * @properties: Whether to add a second argument with object properties
*
- * Notify listeners about event related with newly found p2p peer device
+ * Notify listeners about event related with p2p peer device
*/
static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
const u8 *dev_addr, const char *interface,
- const char *sig_name)
+ const char *sig_name, int properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -3602,7 +3846,10 @@ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
+ &path) ||
+ (properties && !wpa_dbus_get_object_properties(
+ iface, peer_obj_path, WPAS_DBUS_NEW_IFACE_P2P_PEER,
+ &iter)))
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
else
dbus_connection_send(iface->con, msg, NULL);
@@ -3623,7 +3870,11 @@ void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
{
wpas_dbus_signal_peer(wpa_s, dev_addr,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "DeviceFound");
+ "DeviceFound", FALSE);
+
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceFoundProperties", TRUE);
}
/**
@@ -3638,7 +3889,7 @@ void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
{
wpas_dbus_signal_peer(wpa_s, dev_addr,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "DeviceLost");
+ "DeviceLost", FALSE);
}
/**
@@ -3805,41 +4056,50 @@ void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
wpas_dbus_getter_p2p_group_members,
+ NULL,
NULL
},
{ "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
wpas_dbus_getter_p2p_group,
+ NULL,
NULL
},
{ "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
wpas_dbus_getter_p2p_role,
+ NULL,
NULL
},
{ "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
wpas_dbus_getter_p2p_group_ssid,
+ NULL,
NULL
},
{ "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
wpas_dbus_getter_p2p_group_bssid,
+ NULL,
NULL
},
{ "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
wpas_dbus_getter_p2p_group_frequency,
+ NULL,
NULL
},
{ "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
wpas_dbus_getter_p2p_group_passphrase,
+ NULL,
NULL
},
{ "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
wpas_dbus_getter_p2p_group_psk,
+ NULL,
NULL
},
{ "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
wpas_dbus_getter_p2p_group_vendor_ext,
- wpas_dbus_setter_p2p_group_vendor_ext
+ wpas_dbus_setter_p2p_group_vendor_ext,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
@@ -3966,9 +4226,10 @@ static const struct wpa_dbus_property_desc
wpas_dbus_persistent_group_properties[] = {
{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
wpas_dbus_getter_persistent_group_properties,
- wpas_dbus_setter_persistent_group_properties
+ wpas_dbus_setter_persistent_group_properties,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
/* No signals intended for persistent group objects */
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 6d240ff..d64fcee 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -29,6 +29,7 @@ enum wpas_dbus_prop {
WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
WPAS_DBUS_PROP_BSSS,
WPAS_DBUS_PROP_DISCONNECT_REASON,
+ WPAS_DBUS_PROP_ASSOC_STATUS_CODE,
};
enum wpas_dbus_bss_prop {
@@ -189,8 +190,7 @@ void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
const u8 *src, u16 dev_passwd_id,
u8 go_intent);
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id);
+ int client, int persistent);
void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -400,8 +400,7 @@ static inline void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
static inline void
wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id)
+ int client, int persistent)
{
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 67562a5..e11dd36 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -435,7 +435,8 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
for (i = 0; i < array_len; i++) {
if (!dbus_message_iter_append_basic(&array_iter, type,
- array + i * element_size)) {
+ (const char *) array +
+ i * element_size)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 2.5",
__func__);
@@ -711,9 +712,9 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
*
* Getter for "DebugLevel" property.
*/
-dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_level(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
const char *str;
int idx = wpa_debug_level;
@@ -737,9 +738,9 @@ dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
*
* Getter for "DebugTimestamp" property.
*/
-dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_timestamp(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_timestamp, error);
@@ -756,9 +757,9 @@ dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
*
* Getter for "DebugShowKeys" property.
*/
-dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_show_keys(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_show_keys, error);
@@ -774,8 +775,9 @@ dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
*
* Setter for "DebugLevel" property.
*/
-dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_level(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
const char *str = NULL;
@@ -812,9 +814,9 @@ dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
*
* Setter for "DebugTimestamp" property.
*/
-dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_timestamp(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
dbus_bool_t val;
@@ -838,9 +840,9 @@ dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
*
* Setter for "DebugShowKeys" property.
*/
-dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_show_keys(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
dbus_bool_t val;
@@ -867,9 +869,9 @@ dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
* by dbus clients to return list of registered interfaces objects
* paths
*/
-dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_interfaces(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
@@ -912,8 +914,9 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
* Getter for "EapMethods" property. Handles requests
* by dbus clients to return list of strings with supported EAP methods
*/
-dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_eap_methods(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
char **eap_methods;
size_t num_items = 0;
@@ -948,9 +951,9 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
* return a list of strings with supported capabilities like AP, RSN IBSS,
* and P2P that are determined at compile time.
*/
-dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_global_capabilities(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
size_t num_items = 0;
@@ -1472,10 +1475,7 @@ DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
if (wpa_s->current_ssid != NULL) {
- wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
+ wpas_request_disconnection(wpa_s);
return NULL;
}
@@ -1504,7 +1504,7 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
dbus_message_iter_init(message, &iter);
if (wpa_s->dbus_new_path)
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL) {
wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
__func__);
@@ -1513,9 +1513,6 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
"wpa_supplicant could not add a network on this interface.");
goto err;
}
- wpas_notify_network_added(wpa_s, ssid);
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
@@ -1580,6 +1577,27 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
/**
+ * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: NULL
+ *
+ * Handler function for notifying system there will be a expected disconnect.
+ * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
+ */
+DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
+ struct wpa_global *global)
+{
+ struct wpa_supplicant *wpa_s = global->ifaces;
+
+ for (; wpa_s; wpa_s = wpa_s->next)
+ if (wpa_s->wpa_state >= WPA_ASSOCIATED)
+ wpa_s->own_disconnect_req = 1;
+ return NULL;
+}
+
+
+/**
* wpas_dbus_handler_reattach - Reattach to current AP
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
@@ -1641,8 +1659,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
const char *op;
char *iface, *net_id;
int id;
- struct wpa_ssid *ssid;
- int was_disabled;
+ int result;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
@@ -1665,27 +1682,12 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
goto out;
}
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
reply = wpas_dbus_error_network_unknown(message);
goto out;
}
-
- was_disabled = ssid->disabled;
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- else if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG,
- "Stop ongoing sched_scan to remove network from filters");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
wpa_printf(MSG_ERROR,
"%s[dbus]: error occurred when removing network %d",
__func__, id);
@@ -1854,7 +1856,7 @@ out:
os_free(iface);
return reply;
#else /* IEEE8021X_EAPOL */
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+ wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
return wpas_dbus_error_unknown_error(message, "802.1X not included");
#endif /* IEEE8021X_EAPOL */
}
@@ -2271,6 +2273,35 @@ DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
#endif /* CONFIG_TDLS */
+#ifndef CONFIG_NO_CONFIG_WRITE
+/**
+ * wpas_dbus_handler_save_config - Save configuration to configuration file
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on Success, Otherwise errror message
+ *
+ * Handler function for "SaveConfig" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->conf->update_config) {
+ return wpas_dbus_error_unknown_error(
+ message,
+ "Not allowed to update configuration (update_config=0)");
+ }
+
+ ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+ if (ret)
+ return wpas_dbus_error_unknown_error(
+ message, "Failed to update configuration");
+ return NULL;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
/**
* wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
* @message: Pointer to incoming dbus message
@@ -2338,8 +2369,9 @@ DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
*
* Getter for "Capabilities" property of an interface.
*/
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_capabilities(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_driver_capa capa;
@@ -2585,12 +2617,14 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
&iter_array) ||
!wpa_dbus_dict_string_array_add_element(
&iter_array, "infrastructure") ||
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "ad-hoc") ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ad-hoc")) ||
(res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "ap")) ||
(res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ !wpa_s->conf->p2p_disabled &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "p2p")) ||
!wpa_dbus_dict_end_string_array(&iter_dict,
@@ -2629,8 +2663,9 @@ nomem:
*
* Getter for "State" property.
*/
-dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_state(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *str_state;
@@ -2669,8 +2704,9 @@ dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
*
* Getter for "scanning" property.
*/
-dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_scanning(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2689,8 +2725,9 @@ dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
*
* Getter function for "ApScan" property.
*/
-dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_ap_scan(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
@@ -2709,8 +2746,9 @@ dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
*
* Setter function for "ApScan" property.
*/
-dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_ap_scan(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t ap_scan;
@@ -2738,9 +2776,9 @@ dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
*
* Getter function for "FastReauth" property.
*/
-dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_fast_reauth(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
@@ -2760,9 +2798,9 @@ dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
*
* Setter function for "FastReauth" property.
*/
-dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_fast_reauth(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t fast_reauth;
@@ -2786,9 +2824,9 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
* Getter for "DisconnectReason" property. The reason is negative if it is
* locally generated.
*/
-dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_disconnect_reason(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t reason = wpa_s->disconnect_reason;
@@ -2799,6 +2837,27 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
/**
+ * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AssocStatusCode" property.
+ */
+dbus_bool_t wpas_dbus_getter_assoc_status_code(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t status_code = wpa_s->assoc_status_code;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &status_code, error);
+}
+
+
+/**
* wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -2807,9 +2866,9 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
*
* Getter function for "BSSExpireAge" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_expire_age(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
@@ -2828,9 +2887,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
*
* Setter function for "BSSExpireAge" property.
*/
-dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_bss_expire_age(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_age;
@@ -2857,9 +2916,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
*
* Getter function for "BSSExpireCount" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_expire_count(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
@@ -2878,9 +2937,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
*
* Setter function for "BSSExpireCount" property.
*/
-dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_bss_expire_count(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_count;
@@ -2907,8 +2966,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
*
* Getter function for "Country" property.
*/
-dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_country(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char country[3];
@@ -2932,8 +2992,9 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
*
* Setter function for "Country" property.
*/
-dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_country(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *country;
@@ -2970,9 +3031,9 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
*
* Getter function for "ScanInterval" property.
*/
-dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_scan_interval(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t scan_interval = wpa_s->scan_interval;
@@ -2991,9 +3052,9 @@ dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
*
* Setter function for "ScanInterval" property.
*/
-dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_scan_interval(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t scan_interval;
@@ -3020,8 +3081,9 @@ dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
*
* Getter for "Ifname" property.
*/
-dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *ifname = wpa_s->ifname;
@@ -3040,8 +3102,9 @@ dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Driver" property.
*/
-dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_driver(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *driver;
@@ -3069,9 +3132,9 @@ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
*
* Getter for "CurrentBSS" property.
*/
-dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_current_bss(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
@@ -3097,9 +3160,9 @@ dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
*
* Getter for "CurrentNetwork" property.
*/
-dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_current_network(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
@@ -3125,9 +3188,9 @@ dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
*
* Getter for "CurrentAuthMode" property.
*/
-dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_current_auth_mode(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *eap_mode;
@@ -3143,9 +3206,11 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
"EAP-%s", eap_mode);
auth_mode = eap_mode_buf;
- } else {
+ } else if (wpa_s->current_ssid) {
auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
wpa_s->current_ssid->proto);
+ } else {
+ auth_mode = "UNKNOWN";
}
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -3162,9 +3227,9 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
*
* Getter for "BridgeIfname" property.
*/
-dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bridge_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *bridge_ifname = wpa_s->bridge_ifname;
@@ -3175,6 +3240,30 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
/**
+ * wpas_dbus_getter_config_file - Get interface configuration file path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ConfigFile" property.
+ */
+dbus_bool_t wpas_dbus_getter_config_file(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *confname = "";
+
+ if (wpa_s->confname)
+ confname = wpa_s->confname;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+ &confname, error);
+}
+
+
+/**
* wpas_dbus_getter_bsss - Get array of BSSs objects
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3183,8 +3272,9 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
*
* Getter for "BSSs" property.
*/
-dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bsss(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_bss *bss;
@@ -3240,8 +3330,9 @@ out:
*
* Getter for "Networks" property.
*/
-dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_networks(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_ssid *ssid;
@@ -3303,9 +3394,9 @@ out:
*
* Getter for "PKCS11EnginePath" property.
*/
-dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *pkcs11_engine_path;
@@ -3328,9 +3419,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
*
* Getter for "PKCS11ModulePath" property.
*/
-dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *pkcs11_module_path;
@@ -3353,8 +3444,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
*
* Getter for "Blobs" property.
*/
-dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_blobs(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
@@ -3406,6 +3498,79 @@ dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
}
+dbus_bool_t wpas_dbus_getter_iface_global(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ int ret;
+ char buf[250];
+ char *p = buf;
+
+ if (!property_desc->data) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Unhandled interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
+ sizeof(buf));
+ if (ret < 0)
+ *p = '\0';
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
+ error);
+}
+
+
+dbus_bool_t wpas_dbus_setter_iface_global(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *new_value = NULL;
+ char buf[250];
+ size_t combined_len;
+ int ret;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &new_value))
+ return FALSE;
+
+ combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
+ 3;
+ if (combined_len >= sizeof(buf)) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Interface property %s value too large",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ if (!new_value[0])
+ new_value = "NULL";
+
+ ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
+ new_value);
+ if (os_snprintf_error(combined_len, ret)) {
+ dbus_set_error(error, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+ "Failed to construct new interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Failed to set interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ wpa_supplicant_update_config(wpa_s);
+ return TRUE;
+}
+
+
static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
DBusError *error, const char *func_name)
{
@@ -3432,8 +3597,9 @@ static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
*
* Getter for "BSSID" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_bssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3457,8 +3623,9 @@ dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
*
* Getter for "SSID" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_ssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3482,8 +3649,9 @@ dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Privacy" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_privacy(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3508,8 +3676,9 @@ dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
*
* Getter for "Mode" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_mode(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3549,8 +3718,9 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Level" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_signal(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3575,8 +3745,9 @@ dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
*
* Getter for "Frequency" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_frequency(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3607,8 +3778,9 @@ static int cmp_u8s_desc(const void *a, const void *b)
*
* Getter for "Rates" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_rates(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3647,9 +3819,9 @@ dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
}
-static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
- struct wpa_ie_data *ie_data,
- DBusError *error)
+static dbus_bool_t wpas_dbus_get_bss_security_prop(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
@@ -3780,8 +3952,9 @@ nomem:
*
* Getter for "WPA" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_wpa(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3800,7 +3973,7 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
return FALSE;
}
- return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+ return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
}
@@ -3813,8 +3986,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
*
* Getter for "RSN" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_rsn(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3833,7 +4007,7 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
return FALSE;
}
- return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+ return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
}
@@ -3846,8 +4020,9 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
*
* Getter for "WPS" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_wps(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3902,8 +4077,9 @@ nomem:
*
* Getter for "IEs" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3927,8 +4103,9 @@ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
*
* Getter for BSS age
*/
-dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_age(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3956,8 +4133,9 @@ dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
*
* Getter for "enabled" property of a configured network.
*/
-dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_enabled(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
@@ -3976,8 +4154,9 @@ dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
*
* Setter for "Enabled" property of a configured network.
*/
-dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_enabled(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_supplicant *wpa_s;
@@ -4009,9 +4188,9 @@ dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Properties" property of a configured network.
*/
-dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_network_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
DBusMessageIter variant_iter, dict_iter;
@@ -4071,9 +4250,9 @@ out:
*
* Setter for "Properties" property of a configured network.
*/
-dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_network_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_ssid *ssid = net->ssid;
@@ -4211,3 +4390,147 @@ out:
}
#endif /* CONFIG_AP */
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 *ielems;
+ int len;
+ struct ieee802_11_elems elems;
+ dbus_int32_t frame_id;
+ DBusMessageIter iter, array;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+ if (!ielems || len == 0) {
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
+ }
+
+ if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Parse error");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+ if (!wpa_s->vendor_elem[frame_id]) {
+ wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+ }
+
+ if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Resize error");
+ }
+
+ wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ dbus_int32_t frame_id;
+ const u8 *elem;
+ size_t elem_len;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+ if (!wpa_s->vendor_elem[frame_id]) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "ID value does not exist");
+ }
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
+ elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+ &elem, elem_len) ||
+ !dbus_message_iter_close_container(&iter, &array_iter)) {
+ dbus_message_unref(reply);
+ reply = wpas_dbus_error_no_memory(message);
+ }
+
+ return reply;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 *ielems;
+ int len;
+ struct ieee802_11_elems elems;
+ DBusMessageIter iter, array;
+ dbus_int32_t frame_id;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+ if (!ielems || len == 0) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid value");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+
+ if (len == 1 && *ielems == '*') {
+ wpabuf_free(wpa_s->vendor_elem[frame_id]);
+ wpa_s->vendor_elem[frame_id] = NULL;
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+ }
+
+ if (!wpa_s->vendor_elem[frame_id]) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "ID value does not exist");
+ }
+
+ if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Parse error");
+ }
+
+ if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
+ return NULL;
+
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Not found");
+}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 50f72ec..1d6235d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -10,6 +10,8 @@
#ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
#define CTRL_IFACE_DBUS_NEW_HANDLERS_H
+#include "dbus_new_helpers.h"
+
struct network_handler_args {
struct wpa_supplicant *wpa_s;
struct wpa_ssid *ssid;
@@ -50,39 +52,20 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
struct wpa_global *global);
-dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
+ struct wpa_global *global);
+
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_level);
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_timestamp);
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_show_keys);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_level);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_timestamp);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_show_keys);
+DECLARE_ACCESSOR(wpas_dbus_getter_interfaces);
+DECLARE_ACCESSOR(wpas_dbus_getter_eap_methods);
+DECLARE_ACCESSOR(wpas_dbus_getter_global_capabilities);
+DECLARE_ACCESSOR(wpas_dbus_getter_iface_global);
+DECLARE_ACCESSOR(wpas_dbus_setter_iface_global);
DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -146,150 +129,52 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
struct wpa_supplicant *wpa_s);
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
+DECLARE_ACCESSOR(wpas_dbus_getter_state);
+DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
+DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth);
+DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth);
+DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age);
+DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count);
+DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_count);
+DECLARE_ACCESSOR(wpas_dbus_getter_country);
+DECLARE_ACCESSOR(wpas_dbus_setter_country);
+DECLARE_ACCESSOR(wpas_dbus_getter_scan_interval);
+DECLARE_ACCESSOR(wpas_dbus_setter_scan_interval);
+DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
+DECLARE_ACCESSOR(wpas_dbus_getter_driver);
+DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_auth_mode);
+DECLARE_ACCESSOR(wpas_dbus_getter_bsss);
+DECLARE_ACCESSOR(wpas_dbus_getter_networks);
+DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
+DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
+DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_bssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_mode);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_signal);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_frequency);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_rates);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_wpa);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_rsn);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_enabled);
+DECLARE_ACCESSOR(wpas_dbus_setter_enabled);
+DECLARE_ACCESSOR(wpas_dbus_getter_network_properties);
+DECLARE_ACCESSOR(wpas_dbus_setter_network_properties);
DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -297,20 +182,10 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
struct wpa_supplicant *wpa_s);
-dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_process_credentials);
+DECLARE_ACCESSOR(wpas_dbus_setter_process_credentials);
+DECLARE_ACCESSOR(wpas_dbus_getter_config_methods);
+DECLARE_ACCESSOR(wpas_dbus_setter_config_methods);
DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -321,6 +196,16 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
const char *arg);
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 67c079e..73b9e20 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -364,13 +364,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- NULL, 0, 0)) {
+ 0, 0, NULL, 0, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
- } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
+ 0))
goto inv_args;
out:
@@ -582,7 +583,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, -1, 0, 0, 0);
+ go_intent, freq, 0, -1, 0, 0, 0, 0, NULL, 0);
if (new_pin >= 0) {
char npin[9];
@@ -733,8 +734,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto err;
- if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
- 0) {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
+ 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -807,9 +808,9 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
* P2P Device property accessor methods.
*/
-dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_device_config(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, dict_iter;
@@ -916,9 +917,9 @@ err_no_mem:
}
-dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_device_config(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, iter_dict;
@@ -944,7 +945,8 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
if (os_strcmp(entry.key, "DeviceName") == 0) {
char *devname;
- if (entry.type != DBUS_TYPE_STRING)
+ if (entry.type != DBUS_TYPE_STRING ||
+ os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN)
goto error;
devname = os_strdup(entry.str_value);
@@ -1087,8 +1089,9 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peers(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct p2p_data *p2p = wpa_s->global->p2p;
@@ -1201,8 +1204,9 @@ static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
}
-dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_role(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char *str;
@@ -1224,8 +1228,9 @@ dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
}
-dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
@@ -1243,8 +1248,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
}
-dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peergo(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
@@ -1271,9 +1277,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
* Peer object properties accessor methods
*/
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1309,9 +1315,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1346,9 +1352,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1383,9 +1389,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1420,9 +1426,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1458,6 +1464,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
+ const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
@@ -1483,9 +1490,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1508,9 +1515,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_level(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1533,9 +1540,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1558,9 +1565,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1584,6 +1591,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
+ const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
@@ -1649,9 +1657,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
unsigned int i, num = 0;
@@ -1684,8 +1692,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1709,9 +1718,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1774,9 +1783,9 @@ out_of_memory:
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1842,9 +1851,9 @@ out:
*
* Getter for "PersistentGroups" property.
*/
-dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_persistent_groups(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_ssid *ssid;
@@ -1904,16 +1913,16 @@ out:
*
* Getter for "Properties" property of a persistent group.
*/
-dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
/* Leveraging the fact that persistent group object is still
* represented in same manner as network within.
*/
- return wpas_dbus_getter_network_properties(iter, error, net);
+ return wpas_dbus_getter_network_properties(property_desc, iter, error, net);
}
@@ -1927,9 +1936,9 @@ dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
*
* Setter for "Properties" property of a persistent group.
*/
-dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_ssid *ssid = net->ssid;
@@ -2142,9 +2151,9 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
* Group object properties accessor methods
*/
-dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_members(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_ssid *ssid;
@@ -2211,8 +2220,9 @@ out_of_memory:
}
-dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
@@ -2224,9 +2234,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
u8 role = wpas_get_p2p_role(wpa_s);
@@ -2248,9 +2258,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
u16 op_freq;
@@ -2271,9 +2281,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char *p_pass;
@@ -2292,8 +2302,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
u8 *p_psk = NULL;
@@ -2313,9 +2324,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct hostapd_data *hapd;
@@ -2348,9 +2359,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, iter_dict, array_iter, sub;
@@ -2876,8 +2887,9 @@ DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
#ifdef CONFIG_WIFI_DISPLAY
-dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_global_wfd_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
struct wpabuf *ie;
@@ -2898,8 +2910,9 @@ dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_setter_global_wfd_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
DBusMessageIter variant, array;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 2aecbbe..c4c0261 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -89,139 +89,50 @@ DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
/*
* P2P Device property accessor methods.
*/
-dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_setter_p2p_device_config);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_device_config);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peers);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_role);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peergo);
/*
* P2P Peer properties.
*/
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
- DBusMessageIter *iter, DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
- DBusMessageIter *iter, DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelname);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelnumber);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_serialnumber);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_primary_device_type);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_config_method);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_level);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_capability);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_group_capability);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_secondary_device_types);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vendor_extension);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_ies);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_address);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_groups);
/*
* P2P Group properties
*/
-
-dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_members);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_ssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_bssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_frequency);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_passphrase);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_psk);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_vendor_ext);
+DECLARE_ACCESSOR(wpas_dbus_setter_p2p_group_vendor_ext);
/*
* P2P Persistent Groups and properties
*/
-
-dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_persistent_groups);
+DECLARE_ACCESSOR(wpas_dbus_getter_persistent_group_properties);
+DECLARE_ACCESSOR(wpas_dbus_setter_persistent_group_properties);
DBusMessage * wpas_dbus_handler_add_persistent_group(
DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -233,15 +144,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
DBusMessage *message, struct wpa_supplicant *wpa_s);
#ifdef CONFIG_WIFI_DISPLAY
-
-dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
+DECLARE_ACCESSOR(wpas_dbus_getter_global_wfd_ies);
+DECLARE_ACCESSOR(wpas_dbus_setter_global_wfd_ies);
#endif /* CONFIG_WIFI_DISPLAY */
#endif /* DBUS_NEW_HANDLERS_P2P_H */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index b2251ba..f16e229 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -325,7 +325,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
* @wpa_s: %wpa_supplicant data structure
* Returns: NULL on success or DBus error on failure
*
- * Handler for "Cancel" method call. Returns NULL if WPS cancel successfull
+ * Handler for "Cancel" method call. Returns NULL if WPS cancel successful
* or DBus error on WPS cancel failure
*/
DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
@@ -349,9 +349,9 @@ DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
* true if wps_cred_processing configuration field is not equal to 1 or false
* if otherwise.
*/
-dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_process_credentials(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
@@ -371,9 +371,9 @@ dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
* Setter for "ProcessCredentials" property. Sets credentials_processed on 2
* if boolean argument is true or on 1 if otherwise.
*/
-dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_process_credentials(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t process_credentials, old_pc;
@@ -407,9 +407,9 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
* Getter for "ConfigMethods" property. Returned boolean will be true if
* providing the relevant string worked, or false otherwise.
*/
-dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_config_methods(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char *methods = wpa_s->conf->config_methods;
@@ -431,9 +431,9 @@ dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
* Setter for "ConfigMethods" property. Sets the methods string, apply such
* change and returns true on success. Returns false otherwise.
*/
-dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_config_methods(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char *methods, *new_methods;
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 45623f3..0115e32 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -46,7 +46,7 @@ static dbus_bool_t fill_dict_with_properties(
goto error;
/* An error getting a property fails the request entirely */
- if (!dsc->getter(&entry_iter, error, user_data)) {
+ if (!dsc->getter(dsc, &entry_iter, error, user_data)) {
wpa_printf(MSG_INFO,
"dbus: %s dbus_interface=%s dbus_property=%s getter failed",
__func__, dsc->dbus_interface,
@@ -176,7 +176,7 @@ static DBusMessage * properties_get(DBusMessage *message,
dbus_message_iter_init_append(reply, &iter);
dbus_error_init(&error);
- if (dsc->getter(&iter, &error, user_data) == FALSE) {
+ if (dsc->getter(dsc, &iter, &error, user_data) == FALSE) {
dbus_message_unref(reply);
reply = wpas_dbus_reply_new_from_error(
message, &error, DBUS_ERROR_FAILED,
@@ -213,7 +213,7 @@ static DBusMessage * properties_set(DBusMessage *message,
/* Iter will now point to the property's new value */
dbus_error_init(&error);
- if (dsc->setter(&iter, &error, user_data) == TRUE) {
+ if (dsc->setter(dsc, &iter, &error, user_data) == TRUE) {
/* Success */
reply = dbus_message_new_method_return(message);
} else {
@@ -627,7 +627,8 @@ static dbus_bool_t put_changed_properties(
return FALSE;
dbus_error_init(&error);
- if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
+ if (!dsc->getter(dsc, &entry_iter, &error, obj_dsc->user_data))
+ {
if (dbus_error_is_set(&error)) {
wpa_printf(MSG_ERROR,
"dbus: %s: Cannot get new value of property %s: (%s) %s",
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 6e2c1f1..7b63b28 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -16,9 +16,13 @@ typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
void *user_data);
typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
-typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+struct wpa_dbus_property_desc;
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data);
+#define DECLARE_ACCESSOR(f) \
+dbus_bool_t f(const struct wpa_dbus_property_desc *property_desc, \
+ DBusMessageIter *iter, DBusError *error, void *user_data)
struct wpa_dbus_object_desc {
DBusConnection *connection;
@@ -89,6 +93,8 @@ struct wpa_dbus_property_desc {
WPADBusPropertyAccessor getter;
/* property setter function */
WPADBusPropertyAccessor setter;
+ /* other data */
+ const char *data;
};
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index fba57e6..aee105b 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -38,7 +38,7 @@ static struct interfaces * add_interface(struct dl_list *list,
if (!iface)
return NULL;
iface->dbus_interface = os_strdup(dbus_interface);
- iface->xml = wpabuf_alloc(6000);
+ iface->xml = wpabuf_alloc(15000);
if (iface->dbus_interface == NULL || iface->xml == NULL) {
os_free(iface->dbus_interface);
wpabuf_free(iface->xml);
@@ -257,7 +257,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
DBusMessage *reply;
struct wpabuf *xml;
- xml = wpabuf_alloc(15000);
+ xml = wpabuf_alloc(20000);
if (xml == NULL)
return NULL;
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e8f62ef..e540832 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -717,16 +717,13 @@ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
if (wpa_s->dbus_path)
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL) {
reply = dbus_message_new_error(
message, WPAS_ERROR_ADD_NETWORK_ERROR,
"wpa_supplicant could not add a network on this interface.");
goto out;
}
- wpas_notify_network_added(wpa_s, ssid);
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
/* Construct the object path for this network. */
os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -758,7 +755,7 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
const char *op;
char *iface = NULL, *net_id = NULL;
int id;
- struct wpa_ssid *ssid;
+ int result;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_OBJECT_PATH, &op,
@@ -781,19 +778,12 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
}
id = strtoul(net_id, NULL, 10);
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
reply = wpas_dbus_new_invalid_network_error(message);
goto out;
}
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
reply = dbus_message_new_error(
message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
"error removing the specified on this interface.");
@@ -1069,8 +1059,7 @@ out:
DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpas_request_disconnection(wpa_s);
return wpas_dbus_new_success_reply(message);
}
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 01a8c2c..1d05198 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -31,6 +31,9 @@ CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# QCA vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_QCA=y
+
# driver_nl80211.c requires libnl. If you are compiling it yourself
# you may need to point hostapd to your version of libnl.
#
@@ -267,6 +270,9 @@ CONFIG_BACKEND=file
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
# Select layer 2 packet implementation
# linux = Linux packet socket (default)
# pcap = libpcap/libdnet/WinPcap
@@ -276,6 +282,12 @@ CONFIG_BACKEND=file
# none = Empty template
#CONFIG_L2_PACKET=linux
+# Disable Linux packet socket workaround applicable for station interface
+# in a bridge for EAPOL frames. This should be uncommented only if the kernel
+# is known to not have the regression issue in packet socket behavior with
+# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
+#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
+
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
@@ -455,6 +467,9 @@ CONFIG_PEERKEY=y
# Hotspot 2.0
#CONFIG_HS20=y
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
# Disable roaming in wpa_supplicant
#CONFIG_NO_ROAMING=y
@@ -504,3 +519,32 @@ CONFIG_PEERKEY=y
# OS X builds. This is only for building eapol_test.
#CONFIG_OSX=y
+
+# Automatic Channel Selection
+# This will allow wpa_supplicant to pick the channel automatically when channel
+# is set to "0".
+#
+# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative
+# to "channel=0". This would enable us to eventually add other ACS algorithms in
+# similar way.
+#
+# Automatic selection is currently only done through initialization, later on
+# we hope to do background checks to keep us moving to more ideal channels as
+# time goes by. ACS is currently only supported through the nl80211 driver and
+# your driver must have survey dump capability that is filled by the driver
+# during scanning.
+#
+# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with
+# a newly to create wpa_supplicant.conf variable acs_num_scans.
+#
+# Supported ACS drivers:
+# * ath9k
+# * ath5k
+# * ath10k
+#
+# For more details refer to:
+# http://wireless.kernel.org/en/users/Documentation/acs
+#CONFIG_ACS=y
+
+# Support Multi Band Operation
+#CONFIG_MBO=y
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index e9af6d9..3f22413 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -194,7 +194,7 @@ eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index afb8c3b..13c9f45 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,7 +90,7 @@
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index 47947c1..15400f0 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -345,7 +345,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index 5f7b49d..352d3d2 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -91,7 +91,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index b381e40..faf1f27 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,7 +62,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index d13a5db..403c9b2 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,7 +137,7 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 46c21b5..11e0e90 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -377,13 +377,6 @@
</varlistentry>
<varlistentry>
- <term>-t</term>
- <listitem>
- <para>Include timestamp in debug messages.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>-h</term>
<listitem>
<para>Help. Show a usage message.</para>
@@ -736,7 +729,7 @@ fi
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2015,
+ <para>wpa_supplicant is copyright (c) 2003-2016,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 73768c7..220b7ba 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -100,12 +100,10 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- u32 interval)
+ struct wpa_driver_scan_params *params)
{
if (wpa_s->driver->sched_scan)
- return wpa_s->driver->sched_scan(wpa_s->drv_priv,
- params, interval);
+ return wpa_s->driver->sched_scan(wpa_s->drv_priv, params);
return -1;
}
@@ -160,6 +158,15 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_s->driver->get_seqnum)
+ return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv,
+ addr, idx, seq);
+ return -1;
+}
+
static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
const u8 *addr, int reason_code)
{
@@ -292,7 +299,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
data, data_len, noack,
- freq);
+ freq, NULL, 0);
return -1;
}
@@ -401,7 +408,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
if (wpa_s->driver->if_add)
return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
addr, bss_ctx, NULL, force_ifname,
- if_addr, bridge, 0);
+ if_addr, bridge, 0, 0);
return -1;
}
@@ -726,12 +733,11 @@ static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
- const u8 *cs, size_t cs_len)
+ u64 cs)
{
if (!wpa_s->driver->set_current_cipher_suite)
return -1;
- return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs,
- cs_len);
+ return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs);
}
static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
@@ -912,4 +918,62 @@ static inline int wpa_drv_set_prob_oper_freq(struct wpa_supplicant *wpa_s,
return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq);
}
+static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->abort_scan)
+ return -1;
+ return wpa_s->driver->abort_scan(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
+ u32 filters)
+{
+ if (!wpa_s->driver->configure_data_frame_filters)
+ return -1;
+ return wpa_s->driver->configure_data_frame_filters(wpa_s->drv_priv,
+ filters);
+}
+
+static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type type)
+{
+ if (!wpa_s->driver->get_ext_capab)
+ return -1;
+ return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type,
+ &wpa_s->extended_capa,
+ &wpa_s->extended_capa_mask,
+ &wpa_s->extended_capa_len);
+}
+
+static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
+ unsigned int channel,
+ unsigned int period,
+ unsigned int interval,
+ unsigned int count,
+ const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ if (!wpa_s->driver->p2p_lo_start)
+ return -1;
+ return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period,
+ interval, count, device_types,
+ dev_types_len, ies, ies_len);
+}
+
+static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->p2p_lo_stop)
+ return -1;
+ return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t len)
+{
+ if (!wpa_s->driver->set_default_scan_ies)
+ return -1;
+ return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index dce7d1f..6548bd1 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -14,6 +14,7 @@
#include "common.h"
#include "utils/ext_password.h"
+#include "common/version.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
@@ -192,7 +193,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
return;
}
- radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
+ radius_msg_make_authenticator(msg);
hdr = (const struct eap_hdr *) eap;
pos = (const u8 *) (hdr + 1);
@@ -257,6 +258,13 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
goto fail;
}
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_SERVICE_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
+ RADIUS_SERVICE_TYPE_FRAMED)) {
+ printf("Could not add Service-Type\n");
+ goto fail;
+ }
+
os_snprintf(buf, sizeof(buf), "%s", e->connect_info);
if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
@@ -1239,7 +1247,7 @@ static void eapol_test_terminate(int sig, void *signal_ctx)
static void usage(void)
{
printf("usage:\n"
- "eapol_test [-enWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
+ "eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] "
"[-s<AS secret>]\\\n"
" [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
" [-M<client MAC address>] [-o<server cert file] \\\n"
@@ -1264,6 +1272,7 @@ static void usage(void)
" -W = wait for a control interface monitor before starting\n"
" -S = save configuration after authentication\n"
" -n = no MPPE keys expected\n"
+ " -v = show version\n"
" -t<timeout> = sets timeout in seconds (default: 30 s)\n"
" -C<Connect-Info> = RADIUS Connect-Info (default: "
"CONNECT 11Mbps 802.11b)\n"
@@ -1317,7 +1326,7 @@ int main(int argc, char *argv[])
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:W");
+ c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW");
if (c < 0)
break;
switch (c) {
@@ -1383,6 +1392,9 @@ int main(int argc, char *argv[])
ctrl_iface = optarg;
eapol_test.ctrl_iface = 1;
break;
+ case 'v':
+ printf("eapol_test v" VERSION_STR "\n");
+ return 0;
case 'W':
wait_for_monitor++;
break;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 3af1c7d..abe3b47 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -72,6 +72,7 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
}
+#ifndef CONFIG_NO_SCAN_PROCESSING
/**
* wpas_reenabled_network_time - Time until first network is re-enabled
* @wpa_s: Pointer to wpa_supplicant data
@@ -107,6 +108,7 @@ static int wpas_reenabled_network_time(struct wpa_supplicant *wpa_s)
return res;
}
+#endif /* CONFIG_NO_SCAN_PROCESSING */
void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx)
@@ -279,6 +281,11 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
+#ifdef CONFIG_HS20
+ /* Clear possibly configured frame filters */
+ wpa_drv_configure_frame_filters(wpa_s, 0);
+#endif /* CONFIG_HS20 */
+
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
return;
@@ -303,6 +310,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpa_s->key_mgmt = 0;
wpas_rrm_reset(wpa_s);
+ wpa_s->wnmsleep_used = 0;
}
@@ -564,11 +572,36 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
break;
}
#endif /* CONFIG_IEEE80211W */
+ if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) ==
+ NO_MGMT_FRAME_PROTECTION) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled but AP requires it");
+ break;
+ }
+#ifdef CONFIG_MBO
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) !=
+ NO_MGMT_FRAME_PROTECTION) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled on MBO AP");
+ break;
+ }
+#endif /* CONFIG_MBO */
wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE");
return 1;
}
+#ifdef CONFIG_IEEE80211W
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MFP Required but network not MFP Capable");
+ return 0;
+ }
+#endif /* CONFIG_IEEE80211W */
+
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
proto_match++;
@@ -806,10 +839,10 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
}
-static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
- int i, struct wpa_bss *bss,
- struct wpa_ssid *group,
- int only_first_ssid)
+struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+ int i, struct wpa_bss *bss,
+ struct wpa_ssid *group,
+ int only_first_ssid)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
@@ -817,6 +850,9 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
const u8 *ie;
struct wpa_ssid *ssid;
int osen;
+#ifdef CONFIG_MBO
+ const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
@@ -978,8 +1014,16 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
- if (!bss_is_ess(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network");
+ if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
+ continue;
+ }
+
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
continue;
}
@@ -989,6 +1033,14 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+#ifdef CONFIG_MESH
+ if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not allowed (mesh)");
+ continue;
+ }
+#endif /* CONFIG_MESH */
+
if (!rate_match(wpa_s, bss)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do "
"not match");
@@ -1048,6 +1100,29 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
(unsigned int) diff.usec);
continue;
}
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+ assoc_disallow = wpas_mbo_get_bss_attr(
+ bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallow && assoc_disallow[1] >= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
+ assoc_disallow[2]);
+ continue;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO retry delay has not passed yet");
+ continue;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
/* Matching configuration found */
return ssid;
@@ -1301,6 +1376,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
int min_diff;
+ int to_5ghz;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1356,7 +1432,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
- if (current_bss->level < 0 && current_bss->level > selected->level) {
+ to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
+
+ if (current_bss->level < 0 &&
+ current_bss->level > selected->level + to_5ghz * 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
return 0;
@@ -1375,6 +1454,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
else
min_diff = 5;
}
+ if (to_5ghz) {
+ /* Make it easier to move to 5 GHz band */
+ if (min_diff > 2)
+ min_diff -= 2;
+ else
+ min_diff = 0;
+ }
if (abs(current_bss->level - selected->level) < min_diff) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
"in signal level");
@@ -1417,6 +1503,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return -1;
if (!own_request)
return -1;
+ if (data && data->scan_info.external_scan)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
"scanning again");
wpa_supplicant_req_new_scan(wpa_s, 1, 0);
@@ -1441,7 +1529,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_RANDOM_POOL */
if (own_request && wpa_s->scan_res_handler &&
- (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
+ !(data && data->scan_info.external_scan)) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -1462,9 +1550,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
- wpa_s->own_scan_running, wpa_s->radio->external_scan_running);
+ wpa_s->own_scan_running,
+ data ? data->scan_info.external_scan : 0);
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
- wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+ wpa_s->manual_scan_use_id && wpa_s->own_scan_running &&
+ own_request && !(data && data->scan_info.external_scan)) {
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
wpa_s->manual_scan_id);
wpa_s->manual_scan_use_id = 0;
@@ -1475,7 +1565,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_notify_scan_done(wpa_s, 1);
- if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
+ if (data && data->scan_info.external_scan) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
return 0;
@@ -1504,9 +1594,13 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_wps_update_ap_info(wpa_s, scan_res);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+ wpa_s->wpa_state < WPA_COMPLETED)
+ goto scan_work_done;
+
wpa_scan_results_free(scan_res);
- if (wpa_s->scan_work) {
+ if (own_request && wpa_s->scan_work) {
struct wpa_radio_work *work = wpa_s->scan_work;
wpa_s->scan_work = NULL;
radio_work_done(work);
@@ -1516,7 +1610,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
scan_work_done:
wpa_scan_results_free(scan_res);
- if (wpa_s->scan_work) {
+ if (own_request && wpa_s->scan_work) {
struct wpa_radio_work *work = wpa_s->scan_work;
wpa_s->scan_work = NULL;
radio_work_done(work);
@@ -1547,6 +1641,14 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Avoiding join because we already joined a mesh group");
+ return 0;
+ }
+#endif /* CONFIG_MESH */
+
if (selected) {
int skip;
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
@@ -1556,6 +1658,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
return 0;
}
+ if (ssid != wpa_s->current_ssid &&
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+
if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
return -1;
@@ -1568,13 +1677,6 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
*/
return 1;
} else {
-#ifdef CONFIG_MESH
- if (wpa_s->ifmsh) {
- wpa_msg(wpa_s, MSG_INFO,
- "Avoiding join because we already joined a mesh group");
- return 0;
- }
-#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -1830,6 +1932,50 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_FST
+static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
+ const u8 *ie, size_t ie_len)
+{
+ struct mb_ies_info mb_ies;
+
+ if (!ie || !ie_len || !wpa_s->fst)
+ return -ENOENT;
+
+ os_memset(&mb_ies, 0, sizeof(mb_ies));
+
+ while (ie_len >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+ size_t len;
+
+ len = 2 + ie[1];
+ if (len > ie_len) {
+ wpa_hexdump(MSG_DEBUG, "FST: Truncated IE found",
+ ie, ie_len);
+ break;
+ }
+
+ if (ie[0] == WLAN_EID_MULTI_BAND) {
+ wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+ (unsigned int) len);
+ mb_ies.ies[mb_ies.nof_ies].ie = ie + 2;
+ mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2;
+ mb_ies.nof_ies++;
+ }
+
+ ie_len -= len;
+ ie += len;
+ }
+
+ if (mb_ies.nof_ies > 0) {
+ wpabuf_free(wpa_s->received_mb_ies);
+ wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+#endif /* CONFIG_FST */
+
+
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -1880,6 +2026,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
(os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
(p[0] == WLAN_EID_RSN && p[1] >= 2)) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
@@ -2012,19 +2160,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
-#ifdef CONFIG_FST
- wpabuf_free(wpa_s->received_mb_ies);
- wpa_s->received_mb_ies = NULL;
- if (wpa_s->fst) {
- struct mb_ies_info mb_ies;
-
- wpa_printf(MSG_DEBUG, "Looking for MB IE");
- if (!mb_ies_info_by_ies(&mb_ies, data->assoc_info.resp_ies,
- data->assoc_info.resp_ies_len))
- wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
- }
-#endif /* CONFIG_FST */
-
if (wpa_s->assoc_freq && data->assoc_info.freq &&
wpa_s->assoc_freq != data->assoc_info.freq) {
wpa_printf(MSG_DEBUG, "Operating frequency changed from "
@@ -2063,11 +2198,50 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
}
+static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+#ifdef CONFIG_FST
+ struct assoc_info *ai = data ? &data->assoc_info : NULL;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ const u8 *ieprb, *iebcn;
+
+ wpabuf_free(wpa_s->received_mb_ies);
+ wpa_s->received_mb_ies = NULL;
+
+ if (ai &&
+ !wpas_fst_update_mbie(wpa_s, ai->resp_ies, ai->resp_ies_len)) {
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from Association Response frame");
+ return;
+ }
+
+ if (ai &&
+ !wpas_fst_update_mbie(wpa_s, ai->beacon_ies, ai->beacon_ies_len)) {
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from association event Beacon IEs");
+ return;
+ }
+
+ if (!bss)
+ return;
+
+ ieprb = (const u8 *) (bss + 1);
+ iebcn = ieprb + bss->ie_len;
+
+ if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len))
+ wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss IE");
+ else if (!wpas_fst_update_mbie(wpa_s, iebcn, bss->beacon_ie_len))
+ wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss beacon IE");
+#endif /* CONFIG_FST */
+}
+
+
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
u8 bssid[ETH_ALEN];
- int ft_completed;
+ int ft_completed, already_authorized;
int new_bss = 0;
#ifdef CONFIG_AP
@@ -2123,6 +2297,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
"WPA/RSN IEs not updated");
}
+ wpas_fst_update_mb_assoc(wpa_s, data);
+
#ifdef CONFIG_SME
os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
wpa_s->sme.prev_bssid_set = 1;
@@ -2141,6 +2317,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if (wpa_s->l2)
l2_packet_notify_auth_start(wpa_s->l2);
+ already_authorized = data && data->assoc_info.authorized;
+
/*
* Set portEnabled first to FALSE in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
@@ -2149,11 +2327,12 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* AUTHENTICATED without ever giving chance to EAP state machine to
* reset the state.
*/
- if (!ft_completed) {
+ if (!ft_completed && !already_authorized) {
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
}
- if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
+ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed ||
+ already_authorized)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
/* 802.1X::portControl = Auto */
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2245,7 +2424,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
wpa_s->ibss_rsn == NULL) {
- wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+ wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid);
if (!wpa_s->ibss_rsn) {
wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
wpa_supplicant_deauthenticate(
@@ -2339,6 +2518,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
struct wpa_bss *fast_reconnect = NULL;
struct wpa_ssid *fast_reconnect_ssid = NULL;
struct wpa_ssid *last_ssid;
+ struct wpa_bss *curr = NULL;
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -2354,6 +2534,19 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
return;
}
+ if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+ reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY &&
+ locally_generated)
+ /*
+ * Remove the inactive AP (which is probably out of range) from
+ * the BSS list after marking disassociation. In particular
+ * mac80211-based drivers use the
+ * WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in
+ * locally generated disconnection events for cases where the
+ * AP does not reply anymore.
+ */
+ curr = wpa_s->current_bss;
+
if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
@@ -2364,7 +2557,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS ||
- wpas_wps_searching(wpa_s))) {
+ wpas_wps_searching(wpa_s) ||
+ wpas_wps_reenable_networks_pending(wpa_s))) {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
"reconnect (wps=%d/%d wpa_state=%d)",
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
@@ -2414,6 +2608,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
last_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
+ if (curr)
+ wpa_bss_remove(wpa_s, curr, "Connection to AP lost");
+
if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
wpa_s->current_ssid = last_ssid;
@@ -2424,7 +2621,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
!disallowed_bssid(wpa_s, fast_reconnect->bssid) &&
!disallowed_ssid(wpa_s, fast_reconnect->ssid,
fast_reconnect->ssid_len) &&
- !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) {
+ !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
+ !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
#ifndef CONFIG_NO_SCAN_PROCESSING
wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
if (wpa_supplicant_connect(wpa_s, fast_reconnect,
@@ -2622,6 +2820,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched) {
+ wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ break;
+ }
+#endif /* CONFIG_MATCH_IFACE */
+
#ifdef CONFIG_TERMINATE_ONLASTIF
/* check if last interface */
if (!any_interfaces(wpa_s->global->ifaces))
@@ -3007,7 +3212,16 @@ static void wpa_supplicant_update_channel_list(
{
struct wpa_supplicant *ifs;
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+ /*
+ * To allow backwards compatibility with higher level layers that
+ * assumed the REGDOM_CHANGE event is sent over the initially added
+ * interface. Find the highest parent of this interface and use it to
+ * send the event.
+ */
+ for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent)
+ ;
+
+ wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
reg_init_str(info->initiator), reg_type_str(info->type),
info->alpha2[0] ? " alpha2=" : "",
info->alpha2[0] ? info->alpha2 : "");
@@ -3022,14 +3236,16 @@ static void wpa_supplicant_update_channel_list(
free_hw_features(ifs);
ifs->hw.modes = wpa_drv_get_hw_feature_data(
ifs, &ifs->hw.num_modes, &ifs->hw.flags);
- }
- /* Restart sched_scan with updated channel list */
- if (wpa_s->sched_scanning) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Channel list changed restart sched scan.");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ /* Restart PNO/sched_scan with updated channel list */
+ if (ifs->pno) {
+ wpas_stop_pno(ifs);
+ wpas_start_pno(ifs);
+ } else if (ifs->sched_scanning && !ifs->pno_sched_pending) {
+ wpa_dbg(ifs, MSG_DEBUG,
+ "Channel list changed - restart sched_scan");
+ wpas_scan_restart_sched_scan(ifs);
+ }
}
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER);
@@ -3120,6 +3336,14 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa,
+ payload + 1,
+ plen - 1);
+ return;
+ }
+
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
return;
@@ -3209,6 +3433,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
event != EVENT_INTERFACE_STATUS &&
+ event != EVENT_SCAN_RESULTS &&
event != EVENT_SCHED_SCAN_STOPPED) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore event %s (%d) while interface is disabled",
@@ -3237,18 +3462,43 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
switch (event) {
case EVENT_AUTH:
+#ifdef CONFIG_FST
+ if (!wpas_fst_update_mbie(wpa_s, data->auth.ies,
+ data->auth.ies_len))
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from auth IE");
+#endif /* CONFIG_FST */
sme_event_auth(wpa_s, data);
break;
case EVENT_ASSOC:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EVENT_ASSOC - ignore_auth_resp active!");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_supplicant_event_assoc(wpa_s, data);
if (data && data->assoc_info.authorized)
wpa_supplicant_event_assoc_auth(wpa_s, data);
+ if (data) {
+ wpa_msg(wpa_s, MSG_INFO,
+ WPA_EVENT_SUBNET_STATUS_UPDATE "status=%u",
+ data->assoc_info.subnet_status);
+ }
break;
case EVENT_DISASSOC:
wpas_event_disassoc(wpa_s,
data ? &data->disassoc_info : NULL);
break;
case EVENT_DEAUTH:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EVENT_DEAUTH - ignore_auth_resp active!");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpas_event_deauth(wpa_s,
data ? &data->deauth_info : NULL);
break;
@@ -3257,10 +3507,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_STARTED:
- os_get_reltime(&wpa_s->scan_start_time);
- if (wpa_s->own_scan_requested) {
+ if (wpa_s->own_scan_requested ||
+ (data && !data->scan_info.external_scan)) {
struct os_reltime diff;
+ os_get_reltime(&wpa_s->scan_start_time);
os_reltime_sub(&wpa_s->scan_start_time,
&wpa_s->scan_trigger_time, &diff);
wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds",
@@ -3283,7 +3534,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
break;
case EVENT_SCAN_RESULTS:
- if (os_reltime_initialized(&wpa_s->scan_start_time)) {
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_s->scan_res_handler = NULL;
+ wpa_s->own_scan_running = 0;
+ wpa_s->radio->external_scan_running = 0;
+ wpa_s->last_scan_req = NORMAL_SCAN_REQ;
+ break;
+ }
+
+ if (!(data && data->scan_info.external_scan) &&
+ os_reltime_initialized(&wpa_s->scan_start_time)) {
struct os_reltime now, diff;
os_get_reltime(&now);
os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
@@ -3294,8 +3554,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
if (wpa_supplicant_event_scan_results(wpa_s, data))
break; /* interface may have been removed */
- wpa_s->own_scan_running = 0;
- wpa_s->radio->external_scan_running = 0;
+ if (!(data && data->scan_info.external_scan))
+ wpa_s->own_scan_running = 0;
+ if (data && data->scan_info.nl_scan_event)
+ wpa_s->radio->external_scan_running = 0;
radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -3336,13 +3598,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_ASSOC_REJECT:
if (data->assoc_reject.bssid)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "bssid=" MACSTR " status_code=%u",
+ "bssid=" MACSTR " status_code=%u%s",
MAC2STR(data->assoc_reject.bssid),
- data->assoc_reject.status_code);
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "");
else
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "status_code=%u",
- data->assoc_reject.status_code);
+ "status_code=%u%s",
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "");
+ wpa_s->assoc_status_code = data->assoc_reject.status_code;
+ wpas_notify_assoc_status_code(wpa_s);
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_reject(wpa_s, data);
else {
@@ -3398,17 +3664,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
#ifdef CONFIG_OFFCHANNEL
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
- MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
+ MACSTR, MAC2STR(wpa_s->p2pdev->pending_action_dst));
/*
* Catch TX status events for Action frames we sent via group
- * interface in GO mode.
+ * interface in GO mode, or via standalone AP interface.
+ * Note, wpa_s->p2pdev will be the same as wpa_s->parent,
+ * except when the primary interface is used as a GO interface
+ * (for drivers which do not have group interface concurrency)
*/
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
- os_memcmp(wpa_s->parent->pending_action_dst,
+ os_memcmp(wpa_s->p2pdev->pending_action_dst,
data->tx_status.dst, ETH_ALEN) == 0) {
offchannel_send_action_tx_status(
- wpa_s->parent, data->tx_status.dst,
+ wpa_s->p2pdev, data->tx_status.dst,
data->tx_status.data,
data->tx_status.data_len,
data->tx_status.ack ?
@@ -3451,20 +3720,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_from_unknown.wds);
break;
case EVENT_CH_SWITCH:
- if (!data)
- break;
- if (!wpa_s->ap_iface) {
- wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
- "event in non-AP mode");
+ if (!data || !wpa_s->current_ssid)
break;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
+ "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ channel_width_to_string(data->ch_switch.ch_width),
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+
+ wpa_s->assoc_freq = data->ch_switch.freq;
+ wpa_s->current_ssid->frequency = data->ch_switch.freq;
+
+ if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
+ wpa_s->current_ssid->mode ==
+ WPAS_MODE_P2P_GROUP_FORMATION) {
+ wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
}
- wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
- data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset,
- data->ch_switch.ch_width,
- data->ch_switch.cf1,
- data->ch_switch.cf2);
+ wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
break;
#ifdef NEED_AP_MLME
case EVENT_DFS_RADAR_DETECTED:
@@ -3521,12 +3804,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
#ifdef CONFIG_P2P
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
- data->rx_mgmt.frame_len > 24) {
+ data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
const u8 *src = mgmt->sa;
- const u8 *ie = mgmt->u.probe_req.variable;
- size_t ie_len = data->rx_mgmt.frame_len -
- (mgmt->u.probe_req.variable -
- data->rx_mgmt.frame);
+ const u8 *ie;
+ size_t ie_len;
+
+ ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+ ie_len = data->rx_mgmt.frame_len -
+ IEEE80211_HDRLEN;
wpas_p2p_probe_req_rx(
wpa_s, src, mgmt->da,
mgmt->bssid, ie, ie_len,
@@ -3566,11 +3851,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
- data->rx_mgmt.frame_len > 24) {
- const u8 *ie = mgmt->u.probe_req.variable;
- size_t ie_len = data->rx_mgmt.frame_len -
- (mgmt->u.probe_req.variable -
- data->rx_mgmt.frame);
+ data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
+ const u8 *ie;
+ size_t ie_len;
+
+ ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+ ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN;
wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
mgmt->bssid, ie, ie_len,
@@ -3713,6 +3999,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_bss_flush(wpa_s);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -3771,15 +4058,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->driver_gtk_rekey.replay_ctr);
break;
case EVENT_SCHED_SCAN_STOPPED:
- wpa_s->pno = 0;
wpa_s->sched_scanning = 0;
- resched = wpa_s->scanning;
+ resched = wpa_s->scanning && wpas_scan_scheduled(wpa_s);
wpa_supplicant_notify_scanning(wpa_s, 0);
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
break;
/*
+ * If the driver stopped scanning without being requested to,
+ * request a new scan to continue scanning for networks.
+ */
+ if (!wpa_s->sched_scan_stop_req &&
+ wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Restart scanning after unexpected sched_scan stop event");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ break;
+ }
+
+ wpa_s->sched_scan_stop_req = 0;
+
+ /*
* Start a new sched scan to continue searching for more SSIDs
* either if timed out or PNO schedule scan is pending.
*/
@@ -3820,8 +4120,72 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->mesh_peer.ie_len);
#endif /* CONFIG_MESH */
break;
+ case EVENT_SURVEY:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface)
+ break;
+ hostapd_event_get_survey(wpa_s->ap_iface,
+ &data->survey_results);
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_ACS
+ if (!wpa_s->ap_iface)
+ break;
+ hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+ &data->acs_selected_channels);
+#endif /* CONFIG_ACS */
+ break;
+ case EVENT_P2P_LO_STOP:
+#ifdef CONFIG_P2P
+ wpa_s->p2p_lo_started = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP
+ P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d",
+ data->p2p_lo_stop.reason_code);
+#endif /* CONFIG_P2P */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
}
}
+
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct wpa_supplicant *wpa_s;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+ if (wpa_s && wpa_s->driver->get_ifindex) {
+ unsigned int ifindex;
+
+ ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+#ifdef CONFIG_MATCH_IFACE
+ else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) {
+ struct wpa_interface *wpa_i;
+
+ wpa_i = wpa_supplicant_match_iface(
+ ctx, data->interface_status.ifname);
+ if (!wpa_i)
+ return;
+ wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
+ os_free(wpa_i);
+ if (wpa_s)
+ wpa_s->matched = 1;
+ }
+#endif /* CONFIG_MATCH_IFACE */
+
+ if (wpa_s)
+ wpa_supplicant_event(wpa_s, event, data);
+}
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 10ecce7..691de03 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -17,6 +17,7 @@
#include "common/wpa_ctrl.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
+#include "config.h"
#include "driver_i.h"
#include "offchannel.h"
#include "gas_query.h"
@@ -25,6 +26,9 @@
/** GAS query timeout in seconds */
#define GAS_QUERY_TIMEOUT_PERIOD 2
+/* GAS query wait-time / duration in ms */
+#define GAS_QUERY_WAIT_TIME_INITIAL 1000
+#define GAS_QUERY_WAIT_TIME_COMEBACK 150
/**
* struct gas_query_pending - Pending GAS query
@@ -37,6 +41,7 @@ struct gas_query_pending {
u8 next_frag_id;
unsigned int wait_comeback:1;
unsigned int offchannel_tx_started:1;
+ unsigned int retry:1;
int freq;
u16 status_code;
struct wpabuf *req;
@@ -63,6 +68,10 @@ struct gas_query {
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_tx_initial_req(struct gas_query *gas,
+ struct gas_query_pending *query);
+static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst);
static int ms_from_time(struct os_reltime *last)
@@ -108,8 +117,6 @@ static const char * gas_result_txt(enum gas_query_result result)
return "PEER_ERROR";
case GAS_QUERY_INTERNAL_ERROR:
return "INTERNAL_ERROR";
- case GAS_QUERY_CANCELLED:
- return "CANCELLED";
case GAS_QUERY_DELETED_AT_DEINIT:
return "DELETED_AT_DEINIT";
}
@@ -151,6 +158,7 @@ static void gas_query_done(struct gas_query *gas,
offchannel_send_action_done(gas->wpa_s);
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
dl_list_del(&query->list);
query->cb(query->ctx, query->addr, query->dialog_token, result,
query->adv_proto, query->resp, query->status_code);
@@ -235,6 +243,13 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
eloop_cancel_timeout(gas_query_timeout, gas, query);
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
gas_query_timeout, gas, query);
+ if (query->wait_comeback && !query->retry) {
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout,
+ gas, query);
+ eloop_register_timeout(
+ 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
+ gas_query_rx_comeback_timeout, gas, query);
+ }
}
if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
eloop_cancel_timeout(gas_query_timeout, gas, query);
@@ -254,10 +269,13 @@ static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
- struct wpabuf *req)
+ struct wpabuf *req, unsigned int wait_time)
{
- unsigned int wait_time;
int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
"freq=%d prot=%d", MAC2STR(query->addr),
@@ -267,12 +285,18 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
*categ = WLAN_ACTION_PROTECTED_DUAL;
}
os_get_reltime(&query->last_oper);
- wait_time = 1000;
if (gas->wpa_s->max_remain_on_chan &&
wait_time > gas->wpa_s->max_remain_on_chan)
wait_time = gas->wpa_s->max_remain_on_chan;
+ if (!gas->wpa_s->conf->gas_address3 ||
+ (gas->wpa_s->current_ssid &&
+ gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+ os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))
+ bssid = query->addr;
+ else
+ bssid = wildcard_bssid;
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
- gas->wpa_s->own_addr, query->addr,
+ gas->wpa_s->own_addr, bssid,
wpabuf_head(req), wpabuf_len(req),
wait_time, gas_query_tx_status, 0);
if (res == 0)
@@ -285,6 +309,7 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
struct gas_query_pending *query)
{
struct wpabuf *req;
+ unsigned int wait_time;
req = gas_build_comeback_req(query->dialog_token);
if (req == NULL) {
@@ -292,7 +317,10 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
return;
}
- if (gas_query_tx(gas, query, req) < 0) {
+ wait_time = (query->retry || !query->offchannel_tx_started) ?
+ GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
+
+ if (gas_query_tx(gas, query, req, wait_time) < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
MACSTR, MAC2STR(query->addr));
gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
@@ -302,6 +330,35 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
}
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+ struct gas_query *gas = eloop_data;
+ struct gas_query_pending *query = user_ctx;
+ int dialog_token;
+
+ wpa_printf(MSG_DEBUG,
+ "GAS: No response to comeback request received (retry=%u)",
+ query->retry);
+ if (gas->current != query || query->retry)
+ return;
+ dialog_token = gas_query_new_dialog_token(gas, query->addr);
+ if (dialog_token < 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "GAS: Retry GAS query due to comeback response timeout");
+ query->retry = 1;
+ query->dialog_token = dialog_token;
+ *(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
+ query->wait_comeback = 0;
+ query->next_frag_id = 0;
+ wpabuf_free(query->adv_proto);
+ query->adv_proto = NULL;
+ eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ gas_query_tx_initial_req(gas, query);
+}
+
+
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
{
struct gas_query *gas = eloop_data;
@@ -319,6 +376,11 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
{
unsigned int secs, usecs;
+ if (comeback_delay > 1 && query->offchannel_tx_started) {
+ offchannel_send_action_done(gas->wpa_s);
+ query->offchannel_tx_started = 0;
+ }
+
secs = (comeback_delay * 1024) / 1000000;
usecs = comeback_delay * 1024 - secs * 1000000;
wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
@@ -371,6 +433,7 @@ static void gas_query_rx_comeback(struct gas_query *gas,
"comeback_delay=%u)",
MAC2STR(query->addr), query->dialog_token, frag_id,
more_frags, comeback_delay);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
@@ -447,8 +510,16 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
if (gas == NULL || len < 4)
return -1;
+ pos = data;
+ action = *pos++;
+ dialog_token = *pos++;
+
+ if (action != WLAN_PA_GAS_INITIAL_RESP &&
+ action != WLAN_PA_GAS_COMEBACK_RESP)
+ return -1; /* Not a GAS response */
+
prot = categ == WLAN_ACTION_PROTECTED_DUAL;
- pmf = pmf_in_use(gas->wpa_s, bssid);
+ pmf = pmf_in_use(gas->wpa_s, sa);
if (prot && !pmf) {
wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
return 0;
@@ -458,14 +529,6 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
return 0;
}
- pos = data;
- action = *pos++;
- dialog_token = *pos++;
-
- if (action != WLAN_PA_GAS_INITIAL_RESP &&
- action != WLAN_PA_GAS_COMEBACK_RESP)
- return -1; /* Not a GAS response */
-
query = gas_query_get_pending(gas, sa, dialog_token);
if (query == NULL) {
wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
@@ -620,11 +683,18 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
}
gas->work = work;
+ gas_query_tx_initial_req(gas, query);
+}
- if (gas_query_tx(gas, query, query->req) < 0) {
+
+static void gas_query_tx_initial_req(struct gas_query *gas,
+ struct gas_query_pending *query)
+{
+ if (gas_query_tx(gas, query, query->req,
+ GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
MACSTR, MAC2STR(query->addr));
- gas_query_free(query, 1);
+ gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
return;
}
gas->current = query;
@@ -633,7 +703,24 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
query->dialog_token);
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
gas_query_timeout, gas, query);
+}
+
+
+static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst)
+{
+ static int next_start = 0;
+ int dialog_token;
+ for (dialog_token = 0; dialog_token < 256; dialog_token++) {
+ if (gas_query_dialog_token_available(
+ gas, dst, (next_start + dialog_token) % 256))
+ break;
+ }
+ if (dialog_token == 256)
+ return -1; /* Too many pending queries */
+ dialog_token = (next_start + dialog_token) % 256;
+ next_start = (dialog_token + 1) % 256;
+ return dialog_token;
}
@@ -658,20 +745,13 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
{
struct gas_query_pending *query;
int dialog_token;
- static int next_start = 0;
if (wpabuf_len(req) < 3)
return -1;
- for (dialog_token = 0; dialog_token < 256; dialog_token++) {
- if (gas_query_dialog_token_available(
- gas, dst, (next_start + dialog_token) % 256))
- break;
- }
- if (dialog_token == 256)
- return -1; /* Too many pending queries */
- dialog_token = (next_start + dialog_token) % 256;
- next_start = (dialog_token + 1) % 256;
+ dialog_token = gas_query_new_dialog_token(gas, dst);
+ if (dialog_token < 0)
+ return -1;
query = os_zalloc(sizeof(*query));
if (query == NULL)
@@ -694,26 +774,10 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
query) < 0) {
+ query->req = NULL; /* caller will free this in error case */
gas_query_free(query, 1);
return -1;
}
return dialog_token;
}
-
-
-/**
- * gas_query_cancel - Cancel a pending GAS query
- * @gas: GAS query data from gas_query_init()
- * @dst: Destination MAC address for the query
- * @dialog_token: Dialog token from gas_query_req()
- */
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
-{
- struct gas_query_pending *query;
-
- query = gas_query_get_pending(gas, dst, dialog_token);
- if (query)
- gas_query_done(gas, query, GAS_QUERY_CANCELLED);
-
-}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index ad13490..ef82097 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -29,7 +29,6 @@ enum gas_query_result {
GAS_QUERY_TIMEOUT,
GAS_QUERY_PEER_ERROR,
GAS_QUERY_INTERNAL_ERROR,
- GAS_QUERY_CANCELLED,
GAS_QUERY_DELETED_AT_DEINIT
};
@@ -40,7 +39,6 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code),
void *ctx);
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
#else /* CONFIG_GAS */
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index a1afc85..e88f147 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -25,6 +25,7 @@
#include "gas_query.h"
#include "interworking.h"
#include "hs20_supplicant.h"
+#include "base64.h"
#define OSU_MAX_ITEMS 10
@@ -60,6 +61,46 @@ struct osu_provider {
};
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss = wpa_s->current_bss;
+ u8 *bssid = wpa_s->bssid;
+ const u8 *ie;
+ const u8 *ext_capa;
+ u32 filter = 0;
+
+ if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - BSS " MACSTR
+ " is not a Hotspot 2.0 network", MAC2STR(bssid));
+ return;
+ }
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+
+ /* Check if DGAF disabled bit is zero (5th byte in the IE) */
+ if (!ie || ie[1] < 5)
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract DGAF bit");
+ else if (!(ie[6] & HS20_DGAF_DISABLED))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
+
+ ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+ if (!ext_capa || ext_capa[1] < 2) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract Proxy ARP bit");
+ return;
+ }
+
+ /* Check if Proxy ARP is enabled (2nd byte in the IE) */
+ if (ext_capa[3] & BIT(4))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
+ WPA_DATA_FRAME_FILTER_FLAG_NA;
+
+ wpa_drv_configure_frame_filters(wpa_s, filter);
+}
+
+
void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
{
u8 conf;
@@ -164,8 +205,8 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
}
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len)
+static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
{
struct wpabuf *buf;
@@ -180,13 +221,14 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
- const u8 *payload, size_t payload_len)
+ const u8 *payload, size_t payload_len, int inmem)
{
struct wpabuf *buf;
int ret = 0;
int freq;
struct wpa_bss *bss;
int res;
+ struct icon_entry *icon_entry;
bss = wpa_bss_get_bssid(wpa_s, dst);
if (!bss) {
@@ -210,15 +252,127 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
- ret = -1;
+ return -1;
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
+ if (inmem) {
+ icon_entry = os_zalloc(sizeof(struct icon_entry));
+ if (!icon_entry)
+ return -1;
+ os_memcpy(icon_entry->bssid, dst, ETH_ALEN);
+ icon_entry->file_name = os_malloc(payload_len + 1);
+ if (!icon_entry->file_name) {
+ os_free(icon_entry);
+ return -1;
+ }
+ os_memcpy(icon_entry->file_name, payload, payload_len);
+ icon_entry->file_name[payload_len] = '\0';
+ icon_entry->dialog_token = res;
+
+ dl_list_add(&wpa_s->icon_head, &icon_entry->list);
+ }
+
return ret;
}
+static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ const char *file_name)
+{
+ struct icon_entry *icon;
+
+ dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
+ if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 &&
+ os_strcmp(icon->file_name, file_name) == 0 && icon->image)
+ return icon;
+ }
+
+ return NULL;
+}
+
+
+int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name, size_t offset, size_t size,
+ char *reply, size_t buf_len)
+{
+ struct icon_entry *icon;
+ size_t out_size;
+ unsigned char *b64;
+ size_t b64_size;
+ int reply_size;
+
+ wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)",
+ MAC2STR(bssid), file_name, (unsigned int) offset,
+ (unsigned int) size, (unsigned int) buf_len);
+
+ icon = hs20_find_icon(wpa_s, bssid, file_name);
+ if (!icon || !icon->image || offset >= icon->image_len)
+ return -1;
+ if (size > icon->image_len - offset)
+ size = icon->image_len - offset;
+ out_size = buf_len - 3 /* max base64 padding */;
+ if (size * 4 > out_size * 3)
+ size = out_size * 3 / 4;
+ if (size == 0)
+ return -1;
+
+ b64 = base64_encode(&icon->image[offset], size, &b64_size);
+ if (b64 && buf_len >= b64_size) {
+ os_memcpy(reply, b64, b64_size);
+ reply_size = b64_size;
+ } else {
+ reply_size = -1;
+ }
+ os_free(b64);
+ return reply_size;
+}
+
+
+static void hs20_free_icon_entry(struct icon_entry *icon)
+{
+ wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR
+ " dialog_token=%u file_name=%s image_len=%u",
+ MAC2STR(icon->bssid), icon->dialog_token,
+ icon->file_name ? icon->file_name : "N/A",
+ (unsigned int) icon->image_len);
+ os_free(icon->file_name);
+ os_free(icon->image);
+ os_free(icon);
+}
+
+
+int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name)
+{
+ struct icon_entry *icon, *tmp;
+ int count = 0;
+
+ if (!bssid)
+ wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons");
+ else if (!file_name)
+ wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for "
+ MACSTR, MAC2STR(bssid));
+ else
+ wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for "
+ MACSTR " file name %s", MAC2STR(bssid), file_name);
+
+ dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
+ list) {
+ if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) &&
+ (!file_name ||
+ os_strcmp(icon->file_name, file_name) == 0)) {
+ dl_list_del(&icon->list);
+ hs20_free_icon_entry(icon);
+ count++;
+ }
+ }
+ return count == 0 ? -1 : 0;
+}
+
+
static void hs20_set_osu_access_permission(const char *osu_dir,
const char *fname)
{
@@ -243,16 +397,53 @@ static void hs20_set_osu_access_permission(const char *osu_dir,
}
}
+
+static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s,
+ struct icon_entry *new_icon)
+{
+ struct icon_entry *icon, *tmp;
+
+ dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
+ list) {
+ if (icon == new_icon)
+ continue;
+ if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 &&
+ os_strcmp(icon->file_name, new_icon->file_name) == 0) {
+ dl_list_del(&icon->list);
+ hs20_free_icon_entry(icon);
+ }
+ }
+}
+
+
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *pos,
- size_t slen)
+ size_t slen, u8 dialog_token)
{
char fname[256];
int png;
FILE *f;
u16 data_len;
+ struct icon_entry *icon;
+
+ dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
+ if (icon->dialog_token == dialog_token && !icon->image &&
+ os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) {
+ icon->image = os_malloc(slen);
+ if (!icon->image)
+ return -1;
+ os_memcpy(icon->image, pos, slen);
+ icon->image_len = slen;
+ hs20_remove_duplicate_icons(wpa_s, icon);
+ wpa_msg(wpa_s, MSG_INFO,
+ RX_HS20_ICON MACSTR " %s %u",
+ MAC2STR(sa), icon->file_name,
+ (unsigned int) icon->image_len);
+ return 0;
+ }
+ }
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
MAC2STR(sa));
if (slen < 4) {
@@ -315,7 +506,7 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
}
fclose(f);
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
return 0;
}
@@ -358,7 +549,7 @@ static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
- const u8 *data, size_t slen)
+ const u8 *data, size_t slen, u8 dialog_token)
{
const u8 *pos = data;
u8 subtype;
@@ -379,7 +570,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
switch (subtype) {
case HS20_STYPE_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" HS Capability List", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
if (anqp) {
@@ -389,7 +580,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
if (anqp) {
@@ -405,7 +596,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
"Metrics value from " MACSTR, MAC2STR(sa));
break;
}
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
pos[9], pos[10], WPA_GET_LE16(pos + 11));
@@ -415,7 +606,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
if (anqp) {
@@ -425,7 +616,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_OPERATING_CLASS:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
if (anqp) {
@@ -435,7 +626,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_OSU_PROVIDERS_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" OSU Providers list", MAC2STR(sa));
wpa_s->num_prov_found++;
if (anqp) {
@@ -445,7 +636,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_ICON_BINARY_FILE:
- ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen);
+ ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen,
+ dialog_token);
if (wpa_s->fetch_osu_icon_in_progress) {
hs20_osu_icon_fetch_result(wpa_s, ret);
eloop_cancel_timeout(hs20_continue_icon_fetch,
@@ -511,7 +703,10 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
wpa_s->conf->osu_dir);
f = fopen(fname, "w");
if (f == NULL) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not write OSU provider information");
hs20_free_osu_prov(wpa_s);
+ wpa_s->fetch_anqp_in_progress = 0;
return;
}
@@ -579,7 +774,8 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
if (hs20_anqp_send_req(wpa_s, osu->bssid,
BIT(HS20_STYPE_ICON_REQUEST),
(u8 *) icon->filename,
- os_strlen(icon->filename)) < 0) {
+ os_strlen(icon->filename),
+ 0) < 0) {
icon->failed = 1;
continue;
}
@@ -617,7 +813,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
prov->osu_ssid_len = osu_ssid_len;
/* OSU Friendly Name Length */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
"Friendly Name Length");
return;
@@ -633,9 +829,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += len2;
/* OSU Friendly Name Duples */
- while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) {
+ while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
- if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+ if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) {
wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
break;
}
@@ -646,7 +842,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
/* OSU Server URI */
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG,
"HS 2.0: Not enough room for OSU Server URI length");
return;
@@ -661,7 +857,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += uri_len;
/* OSU Method list */
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
"list length");
return;
@@ -681,7 +877,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
/* Icons Available Length */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
"Available Length");
return;
@@ -701,7 +897,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
struct osu_icon *icon = &prov->icon[prov->icon_count];
u8 flen;
- if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
+ if (2 + 2 + 3 + 1 + 1 > pos - pos2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
break;
}
@@ -713,46 +909,46 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
os_memcpy(icon->lang, pos2, 3);
pos2 += 3;
- flen = pos2[0];
- if (flen > pos - pos2 - 1) {
+ flen = *pos2++;
+ if (flen > pos - pos2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
break;
}
- os_memcpy(icon->icon_type, pos2 + 1, flen);
- pos2 += 1 + flen;
+ os_memcpy(icon->icon_type, pos2, flen);
+ pos2 += flen;
- if (pos2 + 1 > pos) {
+ if (pos - pos2 < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
"Filename length");
break;
}
- flen = pos2[0];
- if (flen > pos - pos2 - 1) {
+ flen = *pos2++;
+ if (flen > pos - pos2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
"Filename");
break;
}
- os_memcpy(icon->filename, pos2 + 1, flen);
- pos2 += 1 + flen;
+ os_memcpy(icon->filename, pos2, flen);
+ pos2 += flen;
prov->icon_count++;
}
/* OSU_NAI */
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
return;
}
- osu_nai_len = pos[0];
- if (osu_nai_len > end - pos - 1) {
+ osu_nai_len = *pos++;
+ if (osu_nai_len > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
return;
}
- os_memcpy(prov->osu_nai, pos + 1, osu_nai_len);
- pos += 1 + osu_nai_len;
+ os_memcpy(prov->osu_nai, pos, osu_nai_len);
+ pos += osu_nai_len;
/* OSU Service Description Length */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
"Service Description Length");
return;
@@ -768,20 +964,20 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += len2;
/* OSU Service Description Duples */
- while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
+ while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
u8 descr_len;
- descr_len = pos2[0];
- if (descr_len > pos - pos2 - 1 || descr_len < 3) {
+ descr_len = *pos2++;
+ if (descr_len > pos - pos2 || descr_len < 3) {
wpa_printf(MSG_DEBUG, "Invalid OSU Service "
"Description");
break;
}
f = &prov->serv_desc[prov->serv_desc_count++];
- os_memcpy(f->lang, pos2 + 1, 3);
- os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3);
- pos2 += 1 + descr_len;
+ os_memcpy(f->lang, pos2, 3);
+ os_memcpy(f->text, pos2 + 3, descr_len - 3);
+ pos2 += descr_len;
}
wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
@@ -816,9 +1012,9 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
end = pos + wpabuf_len(prov_anqp);
/* OSU SSID */
- if (pos + 1 > end)
+ if (end - pos < 1)
continue;
- if (pos + 1 + pos[0] > end) {
+ if (1 + pos[0] > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
"OSU SSID");
continue;
@@ -832,7 +1028,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
osu_ssid = pos;
pos += osu_ssid_len;
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
"Number of OSU Providers");
continue;
@@ -842,7 +1038,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
num_providers);
/* OSU Providers */
- while (pos + 2 < end && num_providers > 0) {
+ while (end - pos > 2 && num_providers > 0) {
num_providers--;
len = WPA_GET_LE16(pos);
pos += 2;
@@ -882,7 +1078,7 @@ static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
}
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
{
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
@@ -913,7 +1109,16 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
wpa_s->num_osu_scans = 0;
wpa_s->num_prov_found = 0;
- hs20_start_osu_scan(wpa_s);
+ if (skip_scan) {
+ wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
+ wpa_s->fetch_osu_info = 1;
+ wpa_s->fetch_osu_icon_in_progress = 0;
+
+ interworking_start_fetch_anqp(wpa_s);
+ } else {
+ hs20_start_osu_scan(wpa_s);
+ }
return 0;
}
@@ -1002,8 +1207,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
}
+void hs20_init(struct wpa_supplicant *wpa_s)
+{
+ dl_list_init(&wpa_s->icon_head);
+}
+
+
void hs20_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
hs20_free_osu_prov(wpa_s);
+ if (wpa_s->icon_head.next)
+ hs20_del_icon(wpa_s, NULL, NULL);
}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 85b5120..0dd559f 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -8,17 +8,16 @@
#ifndef HS20_SUPPLICANT_H
#define HS20_SUPPLICANT_H
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
- const u8 *payload, size_t payload_len);
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len);
+ const u8 *payload, size_t payload_len, int inmem);
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
- const u8 *data, size_t slen);
+ const u8 *data, size_t slen, u8 dialog_token);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -32,10 +31,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s);
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan);
void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
void hs20_start_osu_scan(struct wpa_supplicant *wpa_s);
+void hs20_init(struct wpa_supplicant *wpa_s);
void hs20_deinit(struct wpa_supplicant *wpa_s);
+int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name, size_t offset, size_t size,
+ char *reply, size_t buf_len);
+int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name);
#endif /* HS20_SUPPLICANT_H */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index d9d0ae7..53d7d57 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -221,6 +221,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
peer->supp = wpa_sm_init(ctx);
if (peer->supp == NULL) {
wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+ os_free(ctx);
return -1;
}
@@ -230,7 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
- wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL);
peer->supp_ie_len = sizeof(peer->supp_ie);
if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -404,7 +405,7 @@ static void auth_set_eapol(void *ctx, const u8 *addr,
static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
- const u8 *own_addr)
+ const u8 *own_addr, struct wpa_ssid *ssid)
{
struct wpa_auth_config conf;
struct wpa_auth_callbacks cb;
@@ -418,7 +419,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
conf.rsn_pairwise = WPA_CIPHER_CCMP;
conf.wpa_group = WPA_CIPHER_CCMP;
conf.eapol_version = 2;
- conf.wpa_group_rekey = 600;
+ conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = ibss_rsn;
@@ -665,7 +666,8 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
}
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct ibss_rsn *ibss_rsn;
@@ -674,7 +676,7 @@ struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
return NULL;
ibss_rsn->wpa_s = wpa_s;
- if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
+ if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) {
ibss_rsn_deinit(ibss_rsn);
return NULL;
}
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 67fae2d..626c543 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -51,7 +51,8 @@ struct ibss_rsn {
};
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index fd47c17..1fb40c7 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -362,13 +362,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
u8 elen, auth_count, a;
const u8 *e_end;
- if (pos + 3 > end) {
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
return NULL;
}
elen = *pos++;
- if (pos + elen > end || elen < 2) {
+ if (elen > end - pos || elen < 2) {
wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
return NULL;
}
@@ -381,14 +381,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
for (a = 0; a < auth_count; a++) {
u8 id, len;
- if (pos + 2 > end || pos + 2 + pos[1] > end) {
- wpa_printf(MSG_DEBUG, "No room for Authentication "
- "Parameter subfield");
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG,
+ "No room for Authentication Parameter subfield header");
return NULL;
}
id = *pos++;
len = *pos++;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "No room for Authentication Parameter subfield");
+ return NULL;
+ }
switch (id) {
case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
@@ -463,7 +468,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
pos += 2;
- if (pos + len > end || len < 3) {
+ if (len > end - pos || len < 3) {
wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
"(len=%u; left=%u)",
len, (unsigned int) (end - pos));
@@ -473,7 +478,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
r->encoding = *pos++;
realm_len = *pos++;
- if (pos + realm_len > f_end) {
+ if (realm_len > f_end - pos) {
wpa_printf(MSG_DEBUG, "No room for NAI Realm "
"(len=%u; left=%u)",
realm_len, (unsigned int) (f_end - pos));
@@ -485,13 +490,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
return NULL;
pos += realm_len;
- if (pos + 1 > f_end) {
+ if (f_end - pos < 1) {
wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
return NULL;
}
r->eap_count = *pos++;
wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
- if (pos + r->eap_count * 3 > f_end) {
+ if (r->eap_count * 3 > f_end - pos) {
wpa_printf(MSG_DEBUG, "No room for EAP Methods");
return NULL;
}
@@ -746,7 +751,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
return 0;
pos = wpabuf_head_u8(anqp);
end = pos + wpabuf_len(anqp);
- if (pos + 2 > end)
+ if (end - pos < 2)
return 0;
if (*pos != 0) {
wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
@@ -754,7 +759,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
}
pos++;
udhl = *pos++;
- if (pos + udhl > end) {
+ if (udhl > end - pos) {
wpa_printf(MSG_DEBUG, "Invalid UDHL");
return 0;
}
@@ -764,12 +769,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
imsi, mnc_len);
- while (pos + 2 <= end) {
+ while (end - pos >= 2) {
u8 iei, len;
const u8 *l_end;
iei = *pos++;
len = *pos++ & 0x7f;
- if (pos + len > end)
+ if (len > end - pos)
break;
l_end = pos + len;
@@ -780,7 +785,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
pos, len);
num = *pos++;
for (i = 0; i < num; i++) {
- if (pos + 3 > l_end)
+ if (l_end - pos < 3)
break;
if (os_memcmp(pos, plmn, 3) == 0 ||
os_memcmp(pos, plmn2, 3) == 0)
@@ -945,11 +950,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
if (!key_mgmt)
key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
- if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
+ wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
+ wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
}
@@ -1082,12 +1085,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
* OI #1, [OI #2], [OI #3]
*/
- if (pos + 2 > end)
+ if (end - pos < 2)
return 0;
pos++; /* skip Number of ANQP OIs */
lens = *pos++;
- if (pos + (lens & 0x0f) + (lens >> 4) > end)
+ if ((lens & 0x0f) + (lens >> 4) > end - pos)
return 0;
if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
@@ -1121,7 +1124,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
/* Set of <OI Length, OI> duples */
while (pos < end) {
len = *pos++;
- if (pos + len > end)
+ if (len > end - pos)
break;
if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
return 1;
@@ -1182,6 +1185,7 @@ static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_bss *bss)
{
+#ifdef CONFIG_HS20
int res;
unsigned int dl_bandwidth, ul_bandwidth;
const u8 *wan;
@@ -1233,6 +1237,7 @@ static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
return 1;
}
+#endif /* CONFIG_HS20 */
return 0;
}
@@ -1260,9 +1265,11 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_HS20
+
static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
{
- while (pos + 4 <= end) {
+ while (end - pos >= 4) {
if (pos[0] == proto && pos[3] == 1 /* Open */)
return 1;
pos += 4;
@@ -1275,7 +1282,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
u16 port)
{
- while (pos + 4 <= end) {
+ while (end - pos >= 4) {
if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
pos[3] == 1 /* Open */)
return 1;
@@ -1285,10 +1292,13 @@ static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
return 0;
}
+#endif /* CONFIG_HS20 */
+
static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_bss *bss)
{
+#ifdef CONFIG_HS20
int res;
const u8 *capab, *end;
unsigned int i, j;
@@ -1325,6 +1335,7 @@ static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
}
}
}
+#endif /* CONFIG_HS20 */
return 0;
}
@@ -1438,7 +1449,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
os_free(anon);
}
- if (cred->username && cred->username[0] &&
+ if (!ttls && cred->username && cred->username[0] && cred->realm &&
+ !os_strchr(cred->username, '@')) {
+ char *id;
+ size_t buflen;
+ int res;
+
+ buflen = os_strlen(cred->username) + 1 +
+ os_strlen(cred->realm) + 1;
+
+ id = os_malloc(buflen);
+ if (!id)
+ return -1;
+ os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm);
+ res = wpa_config_set_quoted(ssid, "identity", id);
+ os_free(id);
+ if (res < 0)
+ return -1;
+ } else if (cred->username && cred->username[0] &&
wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
return -1;
@@ -1560,9 +1588,8 @@ fail:
}
-static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, int allow_excluded,
- int only_add)
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int only_add)
{
struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
@@ -1570,7 +1597,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
struct nai_realm_eap *eap = NULL;
u16 count, i;
char buf[100];
- int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
+ int excluded = 0, *excl = &excluded;
const char *name;
if (wpa_s->conf->cred == NULL || bss == NULL)
@@ -1584,8 +1611,8 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
}
wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
- " for connection (allow_excluded=%d)",
- MAC2STR(bss->bssid), allow_excluded);
+ " for connection",
+ MAC2STR(bss->bssid));
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
@@ -1603,7 +1630,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1612,7 +1639,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1622,7 +1649,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1635,7 +1662,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1645,7 +1672,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1655,7 +1682,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
}
@@ -1820,13 +1847,6 @@ fail:
}
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int only_add)
-{
- return interworking_connect_helper(wpa_s, bss, 1, only_add);
-}
-
-
#ifdef PCSC_FUNCS
static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
{
@@ -2125,23 +2145,27 @@ int domain_name_list_contains(struct wpabuf *domain_names,
pos = wpabuf_head(domain_names);
end = pos + wpabuf_len(domain_names);
- while (pos + 1 < end) {
- if (pos + 1 + pos[0] > end)
+ while (end - pos > 1) {
+ u8 elen;
+
+ elen = *pos++;
+ if (elen > end - pos)
break;
wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
- pos + 1, pos[0]);
- if (pos[0] == len &&
- os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
+ pos, elen);
+ if (elen == len &&
+ os_strncasecmp(domain, (const char *) pos, len) == 0)
return 1;
- if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') {
- const char *ap = (const char *) (pos + 1);
- int offset = pos[0] - len;
+ if (!exact_match && elen > len && pos[elen - len - 1] == '.') {
+ const char *ap = (const char *) pos;
+ int offset = elen - len;
+
if (os_strncasecmp(domain, ap + offset, len) == 0)
return 1;
}
- pos += 1 + pos[0];
+ pos += elen;
}
return 0;
@@ -2564,11 +2588,13 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
return;
}
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_icon_in_progress) {
wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
hs20_next_osu_icon(wpa_s);
return;
}
+#endif /* CONFIG_HS20 */
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!(bss->caps & IEEE80211_CAP_ESS))
@@ -2602,6 +2628,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
}
if (found == 0) {
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_info) {
if (wpa_s->num_prov_found == 0 &&
wpa_s->fetch_osu_waiting_scan &&
@@ -2614,6 +2641,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
hs20_osu_icon_fetch(wpa_s);
return;
}
+#endif /* CONFIG_HS20 */
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
wpa_s->fetch_anqp_in_progress = 0;
if (wpa_s->network_select)
@@ -2664,10 +2692,11 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids, u32 subtypes)
+ u16 info_ids[], size_t num_ids, u32 subtypes,
+ int get_cell_pref)
{
struct wpabuf *buf;
- struct wpabuf *hs20_buf = NULL;
+ struct wpabuf *extra_buf = NULL;
int ret = 0;
int freq;
struct wpa_bss *bss;
@@ -2690,15 +2719,31 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
#ifdef CONFIG_HS20
if (subtypes != 0) {
- hs20_buf = wpabuf_alloc(100);
- if (hs20_buf == NULL)
+ extra_buf = wpabuf_alloc(100);
+ if (extra_buf == NULL)
return -1;
- hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
+ hs20_put_anqp_req(subtypes, NULL, 0, extra_buf);
}
#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, num_ids, hs20_buf);
- wpabuf_free(hs20_buf);
+#ifdef CONFIG_MBO
+ if (get_cell_pref) {
+ struct wpabuf *mbo;
+
+ mbo = mbo_build_anqp_buf(wpa_s, bss);
+ if (mbo) {
+ if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
+ wpabuf_free(extra_buf);
+ return -1;
+ }
+ wpabuf_put_buf(extra_buf, mbo);
+ wpabuf_free(mbo);
+ }
+ }
+#endif /* CONFIG_MBO */
+
+ buf = anqp_build_req(info_ids, num_ids, extra_buf);
+ wpabuf_free(extra_buf);
if (buf == NULL)
return -1;
@@ -2716,10 +2761,46 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
}
+static void anqp_add_extra(struct wpa_supplicant *wpa_s,
+ struct wpa_bss_anqp *anqp, u16 info_id,
+ const u8 *data, size_t slen)
+{
+ struct wpa_bss_anqp_elem *tmp, *elem = NULL;
+
+ if (!anqp)
+ return;
+
+ dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem,
+ list) {
+ if (tmp->infoid == info_id) {
+ elem = tmp;
+ break;
+ }
+ }
+
+ if (!elem) {
+ elem = os_zalloc(sizeof(*elem));
+ if (!elem)
+ return;
+ elem->infoid = info_id;
+ dl_list_add(&anqp->anqp_elems, &elem->list);
+ } else {
+ wpabuf_free(elem->payload);
+ }
+
+ elem->payload = wpabuf_alloc_copy(data, slen);
+ if (!elem->payload) {
+ dl_list_del(&elem->list);
+ os_free(elem);
+ }
+}
+
+
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
u16 info_id,
- const u8 *data, size_t slen)
+ const u8 *data, size_t slen,
+ u8 dialog_token)
{
const u8 *pos = data;
struct wpa_bss_anqp *anqp = NULL;
@@ -2732,7 +2813,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
switch (info_id) {
case ANQP_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" ANQP Capability list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
pos, slen);
@@ -2742,7 +2823,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_VENUE_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
if (anqp) {
@@ -2751,7 +2832,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_NETWORK_AUTH_TYPE:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Network Authentication Type information",
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
@@ -2762,7 +2843,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_ROAMING_CONSORTIUM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
@@ -2772,7 +2853,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" IP Address Type Availability information",
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
@@ -2784,7 +2865,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_NAI_REALM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
if (anqp) {
@@ -2793,7 +2874,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
@@ -2803,7 +2884,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_DOMAIN_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
if (anqp) {
@@ -2829,7 +2910,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
switch (type) {
case HS20_ANQP_OUI_TYPE:
hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
- pos, slen);
+ pos, slen,
+ dialog_token);
break;
default:
wpa_msg(wpa_s, MSG_DEBUG,
@@ -2849,6 +2931,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
default:
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Unsupported ANQP Info ID %u", info_id);
+ anqp_add_extra(wpa_s, anqp, info_id, data, slen);
break;
}
}
@@ -2871,8 +2954,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
" dialog_token=%u result=%d status_code=%u",
MAC2STR(dst), dialog_token, result, status_code);
if (result != GAS_QUERY_SUCCESS) {
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
+#endif /* CONFIG_HS20 */
anqp_result = "FAILURE";
goto out;
}
@@ -2882,8 +2967,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Unexpected Advertisement Protocol in response");
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
+#endif /* CONFIG_HS20 */
anqp_result = "INVALID_FRAME";
goto out;
}
@@ -2927,12 +3014,14 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
goto out_parse_done;
}
interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
- slen);
+ slen, dialog_token);
pos += slen;
}
out_parse_done:
+#ifdef CONFIG_HS20
hs20_notify_parse_done(wpa_s);
+#endif /* CONFIG_HS20 */
out:
wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
MAC2STR(dst), anqp_result);
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 3743dc0..3d22292 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -12,7 +12,8 @@
enum gas_query_result;
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids, u32 subtypes);
+ u16 info_ids[], size_t num_ids, u32 subtypes,
+ int get_cell_pref);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
diff --git a/wpa_supplicant/libwpa_test.c b/wpa_supplicant/libwpa_test.c
new file mode 100644
index 0000000..e51ab72
--- /dev/null
+++ b/wpa_supplicant/libwpa_test.c
@@ -0,0 +1,32 @@
+/*
+ * libwpa_test - Test program for libwpa_client.* library linking
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common/wpa_ctrl.h"
+
+int main(int argc, char *argv[])
+{
+ struct wpa_ctrl *ctrl;
+
+ ctrl = wpa_ctrl_open("foo");
+ if (!ctrl)
+ return -1;
+ if (wpa_ctrl_attach(ctrl) == 0)
+ wpa_ctrl_detach(ctrl);
+ if (wpa_ctrl_pending(ctrl)) {
+ char buf[10];
+ size_t len;
+
+ len = sizeof(buf);
+ wpa_ctrl_recv(ctrl, buf, &len);
+ }
+ wpa_ctrl_close(ctrl);
+
+ return 0;
+}
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index d5d47e1..e08c2fd 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -65,41 +65,44 @@ static void usage(void)
" -B = run daemon in the background\n"
" -c = Configuration file\n"
" -C = ctrl_interface parameter (only used if -c is not)\n"
- " -i = interface name\n"
- " -I = additional configuration file\n"
" -d = increase debugging verbosity (-dd even more)\n"
" -D = driver name (can be multiple drivers: nl80211,wext)\n"
- " -e = entropy file\n");
+ " -e = entropy file\n"
#ifdef CONFIG_DEBUG_FILE
- printf(" -f = log output to debug file instead of stdout\n");
+ " -f = log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
- printf(" -g = global ctrl_interface\n"
+ " -g = global ctrl_interface\n"
" -G = global ctrl_interface group\n"
- " -K = include keys (passwords, etc.) in debug output\n");
-#ifdef CONFIG_DEBUG_SYSLOG
- printf(" -s = log output to syslog instead of stdout\n");
-#endif /* CONFIG_DEBUG_SYSLOG */
-#ifdef CONFIG_DEBUG_LINUX_TRACING
- printf(" -T = record to Linux tracing in addition to logging\n");
- printf(" (records all messages regardless of debug verbosity)\n");
-#endif /* CONFIG_DEBUG_LINUX_TRACING */
- printf(" -t = include timestamp in debug messages\n"
" -h = show this help text\n"
+ " -i = interface name\n"
+ " -I = additional configuration file\n"
+ " -K = include keys (passwords, etc.) in debug output\n"
" -L = show license (BSD)\n"
+#ifdef CONFIG_P2P
+ " -m = Configuration file for the P2P Device interface\n"
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ " -M = start describing new matching interface\n"
+#endif /* CONFIG_MATCH_IFACE */
+ " -N = start describing new interface\n"
" -o = override driver parameter for new interfaces\n"
" -O = override ctrl_interface parameter for new interfaces\n"
" -p = driver parameters\n"
" -P = PID file\n"
- " -q = decrease debugging verbosity (-qq even less)\n");
+ " -q = decrease debugging verbosity (-qq even less)\n"
+#ifdef CONFIG_DEBUG_SYSLOG
+ " -s = log output to syslog instead of stdout\n"
+#endif /* CONFIG_DEBUG_SYSLOG */
+ " -t = include timestamp in debug messages\n"
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ " -T = record to Linux tracing in addition to logging\n"
+ " (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
#ifdef CONFIG_DBUS
- printf(" -u = enable DBus control interface\n");
+ " -u = enable DBus control interface\n"
#endif /* CONFIG_DBUS */
- printf(" -v = show version\n"
- " -W = wait for a control interface monitor before starting\n"
-#ifdef CONFIG_P2P
- " -m = Configuration file for the P2P Device interface\n"
-#endif /* CONFIG_P2P */
- " -N = start describing new interface\n");
+ " -v = show version\n"
+ " -W = wait for a control interface monitor before starting\n");
printf("example:\n"
" wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
@@ -153,6 +156,28 @@ static void wpa_supplicant_fd_workaround(int start)
}
+#ifdef CONFIG_MATCH_IFACE
+static int wpa_supplicant_init_match(struct wpa_global *global)
+{
+ /*
+ * The assumption is that the first driver is the primary driver and
+ * will handle the arrival / departure of interfaces.
+ */
+ if (wpa_drivers[0]->global_init && !global->drv_priv[0]) {
+ global->drv_priv[0] = wpa_drivers[0]->global_init(global);
+ if (!global->drv_priv[0]) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize driver '%s'",
+ wpa_drivers[0]->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MATCH_IFACE */
+
+
int main(int argc, char *argv[])
{
int c, i;
@@ -176,7 +201,7 @@ int main(int argc, char *argv[])
for (;;) {
c = getopt(argc, argv,
- "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -282,6 +307,20 @@ int main(int argc, char *argv[])
case 'W':
params.wait_for_monitor++;
break;
+#ifdef CONFIG_MATCH_IFACE
+ case 'M':
+ params.match_iface_count++;
+ iface = os_realloc_array(params.match_ifaces,
+ params.match_iface_count,
+ sizeof(struct wpa_interface));
+ if (!iface)
+ goto out;
+ params.match_ifaces = iface;
+ iface = &params.match_ifaces[params.match_iface_count -
+ 1];
+ os_memset(iface, 0, sizeof(*iface));
+ break;
+#endif /* CONFIG_MATCH_IFACE */
case 'N':
iface_count++;
iface = os_realloc_array(ifaces, iface_count,
@@ -328,6 +367,9 @@ int main(int argc, char *argv[])
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && (params.ctrl_interface ||
+#ifdef CONFIG_MATCH_IFACE
+ params.match_iface_count ||
+#endif /* CONFIG_MATCH_IFACE */
params.dbus_ctrl_interface))
break;
usage();
@@ -341,6 +383,11 @@ int main(int argc, char *argv[])
}
}
+#ifdef CONFIG_MATCH_IFACE
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_init_match(global);
+#endif /* CONFIG_MATCH_IFACE */
+
if (exitcode == 0)
exitcode = wpa_supplicant_run(global);
@@ -351,6 +398,9 @@ int main(int argc, char *argv[])
out:
wpa_supplicant_fd_workaround(0);
os_free(ifaces);
+#ifdef CONFIG_MATCH_IFACE
+ os_free(params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
os_free(params.pid_file);
os_program_deinit();
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
new file mode 100644
index 0000000..7e049be
--- /dev/null
+++ b/wpa_supplicant/mbo.c
@@ -0,0 +1,836 @@
+/*
+ * wpa_supplicant - MBO
+ *
+ * Copyright(c) 2015 Intel Deutschland GmbH
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+
+/* type + length + oui + oui type */
+#define MBO_IE_HEADER 6
+
+
+static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason)
+{
+ if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE)
+ return -1;
+
+ /* Only checking the validity of the channel and oper_class */
+ if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
+{
+ const u8 *mbo, *end;
+
+ if (!bss)
+ return NULL;
+
+ mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (!mbo)
+ return NULL;
+
+ end = mbo + 2 + mbo[1];
+ mbo += MBO_IE_HEADER;
+
+ return get_ie(mbo, end - mbo, attr);
+}
+
+
+static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo,
+ u8 start, u8 end)
+{
+ u8 i;
+
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class);
+
+ for (i = start; i < end; i++)
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan);
+
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference);
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason);
+}
+
+
+static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo, u8 start, u8 end)
+{
+ size_t size = end - start + 3;
+
+ if (size + 2 > wpabuf_tailroom(mbo))
+ return;
+
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+ wpabuf_put_u8(mbo, size); /* Length */
+
+ wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
+}
+
+
+static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len)
+{
+ wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(mbo, len); /* Length */
+ wpabuf_put_be24(mbo, OUI_WFA);
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+}
+
+
+static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo, u8 start,
+ u8 end)
+{
+ size_t size = end - start + 7;
+
+ if (size + 2 > wpabuf_tailroom(mbo))
+ return;
+
+ wpas_mbo_non_pref_chan_subelem_hdr(mbo, size);
+ wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
+}
+
+
+static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo, int subelement)
+{
+ u8 i, start = 0;
+ struct wpa_mbo_non_pref_channel *start_pref;
+
+ if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
+ if (subelement)
+ wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
+ return;
+ }
+ start_pref = &wpa_s->non_pref_chan[0];
+
+ for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
+ struct wpa_mbo_non_pref_channel *non_pref = NULL;
+
+ if (i < wpa_s->non_pref_chan_num)
+ non_pref = &wpa_s->non_pref_chan[i];
+ if (!non_pref ||
+ non_pref->oper_class != start_pref->oper_class ||
+ non_pref->reason != start_pref->reason ||
+ non_pref->preference != start_pref->preference) {
+ if (subelement)
+ wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
+ start, i);
+ else
+ wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start,
+ i);
+
+ if (!non_pref)
+ return;
+
+ start = i;
+ start_pref = non_pref;
+ }
+ }
+}
+
+
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+{
+ struct wpabuf *mbo;
+ int res;
+
+ if (len < MBO_IE_HEADER + 3 + 7)
+ return 0;
+
+ /* Leave room for the MBO IE header */
+ mbo = wpabuf_alloc(len - MBO_IE_HEADER);
+ if (!mbo)
+ return 0;
+
+ /* Add non-preferred channels attribute */
+ wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0);
+
+ /*
+ * Send cellular capabilities attribute even if AP does not advertise
+ * cellular capabilities.
+ */
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA);
+ wpabuf_put_u8(mbo, 1);
+ wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa);
+
+ res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
+ if (!res)
+ wpa_printf(MSG_ERROR, "Failed to add MBO IE");
+
+ wpabuf_free(mbo);
+ return res;
+}
+
+
+static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
+{
+ struct wpabuf *buf;
+ int res;
+
+ /*
+ * Send WNM-Notification Request frame only in case of a change in
+ * non-preferred channels list during association, if the AP supports
+ * MBO.
+ */
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss ||
+ !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
+ return;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+ wpa_s->mbo_wnm_token++;
+ if (wpa_s->mbo_wnm_token == 0)
+ wpa_s->mbo_wnm_token++;
+ wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
+
+ wpabuf_put_data(buf, data, len);
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG,
+ "Failed to send WNM-Notification Request frame with non-preferred channel list");
+
+ wpabuf_free(buf);
+}
+
+
+static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(512);
+ if (!buf)
+ return;
+
+ wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
+ wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
+ wpabuf_len(buf));
+ wpabuf_free(buf);
+}
+
+
+static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
+ struct wpa_mbo_non_pref_channel *b)
+{
+ return a->oper_class == b->oper_class && a->chan == b->chan;
+}
+
+
+/*
+ * wpa_non_pref_chan_cmp - Compare two channels for sorting
+ *
+ * In MBO IE non-preferred channel subelement we can put many channels in an
+ * attribute if they are in the same operating class and have the same
+ * preference and reason. To make it easy for the functions that build
+ * the IE attributes and WNM Request subelements, save the channels sorted
+ * by their oper_class and reason.
+ */
+static int wpa_non_pref_chan_cmp(const void *_a, const void *_b)
+{
+ const struct wpa_mbo_non_pref_channel *a = _a, *b = _b;
+
+ if (a->oper_class != b->oper_class)
+ return a->oper_class - b->oper_class;
+ if (a->reason != b->reason)
+ return a->reason - b->reason;
+ return a->preference - b->preference;
+}
+
+
+int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
+ const char *non_pref_chan)
+{
+ char *cmd, *token, *context = NULL;
+ struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans;
+ size_t num = 0, size = 0;
+ unsigned i;
+
+ wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%s",
+ non_pref_chan ? non_pref_chan : "N/A");
+
+ /*
+ * The shortest channel configuration is 10 characters - commas, 3
+ * colons, and 4 values that one of them (oper_class) is 2 digits or
+ * more.
+ */
+ if (!non_pref_chan || os_strlen(non_pref_chan) < 10)
+ goto update;
+
+ cmd = os_strdup(non_pref_chan);
+ if (!cmd)
+ return -1;
+
+ while ((token = str_token(cmd, " ", &context))) {
+ struct wpa_mbo_non_pref_channel *chan;
+ int ret;
+ unsigned int _oper_class;
+ unsigned int _chan;
+ unsigned int _preference;
+ unsigned int _reason;
+
+ if (num == size) {
+ size = size ? size * 2 : 1;
+ tmp_chans = os_realloc_array(chans, size,
+ sizeof(*chans));
+ if (!tmp_chans) {
+ wpa_printf(MSG_ERROR,
+ "Couldn't reallocate non_pref_chan");
+ goto fail;
+ }
+ chans = tmp_chans;
+ }
+
+ chan = &chans[num];
+
+ ret = sscanf(token, "%u:%u:%u:%u", &_oper_class,
+ &_chan, &_preference, &_reason);
+ if (ret != 4 ||
+ _oper_class > 255 || _chan > 255 ||
+ _preference > 255 || _reason > 65535 ) {
+ wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s",
+ token);
+ goto fail;
+ }
+ chan->oper_class = _oper_class;
+ chan->chan = _chan;
+ chan->preference = _preference;
+ chan->reason = _reason;
+
+ if (wpas_mbo_validate_non_pref_chan(chan->oper_class,
+ chan->chan, chan->reason)) {
+ wpa_printf(MSG_ERROR,
+ "Invalid non_pref_chan: oper class %d chan %d reason %d",
+ chan->oper_class, chan->chan, chan->reason);
+ goto fail;
+ }
+
+ for (i = 0; i < num; i++)
+ if (wpa_non_pref_chan_is_eq(chan, &chans[i]))
+ break;
+ if (i != num) {
+ wpa_printf(MSG_ERROR,
+ "oper class %d chan %d is duplicated",
+ chan->oper_class, chan->chan);
+ goto fail;
+ }
+
+ num++;
+ }
+
+ os_free(cmd);
+
+ if (chans) {
+ qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel),
+ wpa_non_pref_chan_cmp);
+ }
+
+update:
+ os_free(wpa_s->non_pref_chan);
+ wpa_s->non_pref_chan = chans;
+ wpa_s->non_pref_chan_num = num;
+ wpas_mbo_non_pref_chan_changed(wpa_s);
+
+ return 0;
+
+fail:
+ os_free(chans);
+ os_free(cmd);
+ return -1;
+}
+
+
+void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie)
+{
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 7);
+ wpabuf_put_be24(ie, OUI_WFA);
+ wpabuf_put_u8(ie, MBO_OUI_TYPE);
+
+ wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA);
+ wpabuf_put_u8(ie, 1);
+ wpabuf_put_u8(ie, wpa_s->conf->mbo_cell_capa);
+}
+
+
+enum chan_allowed {
+ NOT_ALLOWED, ALLOWED
+};
+
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+ unsigned int *flags)
+{
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].chan == chan)
+ break;
+ }
+
+ if (i == mode->num_channels ||
+ (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
+ return NOT_ALLOWED;
+
+ if (flags)
+ *flags = mode->channels[i].flag;
+
+ return ALLOWED;
+}
+
+
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_channels[] = {42, 58, 106, 122, 138, 155};
+ size_t i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ /*
+ * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+ * so the center channel is 6 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 6 &&
+ channel <= center_channels[i] + 6)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+
+ center_chan = get_center_80mhz(mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* check all the channels are available */
+ for (i = 0; i < 4; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 6 + i * 4;
+
+ if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
+ (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
+ (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
+ (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
+ return NOT_ALLOWED;
+ }
+
+ return ALLOWED;
+}
+
+
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_channels[] = { 50, 114 };
+ unsigned int i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ /*
+ * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+ * so the center channel is 14 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 14 &&
+ channel <= center_channels[i] + 14)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+
+ center_chan = get_center_160mhz(mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* Check all the channels are available */
+ for (i = 0; i < 8; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 14 + i * 4;
+
+ if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
+ (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
+ (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
+ (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
+ (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
+ (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
+ (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
+ (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
+ return NOT_ALLOWED;
+ }
+
+ return ALLOWED;
+}
+
+
+static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ unsigned int flag = 0;
+ enum chan_allowed res, res2;
+
+ res2 = res = allow_channel(mode, channel, &flag);
+ if (bw == BW40MINUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+ return NOT_ALLOWED;
+ res2 = allow_channel(mode, channel - 4, NULL);
+ } else if (bw == BW40PLUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+ return NOT_ALLOWED;
+ res2 = allow_channel(mode, channel + 4, NULL);
+ } else if (bw == BW80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
+ } else if (bw == BW160) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 160 MHz specific version.
+ */
+ res2 = res = verify_160mhz(mode, channel);
+ } else if (bw == BW80P80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
+ }
+
+ if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ return ALLOWED;
+}
+
+
+static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+ const struct oper_class_map *op_class)
+{
+ int chan;
+ size_t i;
+ struct hostapd_hw_modes *mode;
+ int found;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+ if (!mode)
+ return 0;
+
+ if (op_class->op_class == 128) {
+ u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ if (verify_channel(mode, channels[i], op_class->bw) ==
+ ALLOWED)
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (op_class->op_class == 129) {
+ /* Check if either 160 MHz channels is allowed */
+ return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 114, op_class->bw) == ALLOWED;
+ }
+
+ if (op_class->op_class == 130) {
+ /* Need at least two non-contiguous 80 MHz segments */
+ found = 0;
+
+ if (verify_channel(mode, 42, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 58, op_class->bw) == ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 122, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 138, op_class->bw) == ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
+ verify_channel(mode, 138, op_class->bw) == ALLOWED)
+ found++;
+ if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
+ found++;
+
+ if (found >= 2)
+ return 1;
+
+ return 0;
+ }
+
+ found = 0;
+ for (chan = op_class->min_chan; chan <= op_class->max_chan;
+ chan += op_class->inc) {
+ if (verify_channel(mode, chan, op_class->bw) == ALLOWED) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+ size_t len)
+{
+ struct wpabuf *buf;
+ u8 op, current, chan;
+ u8 *ie_len;
+ int res;
+
+ /*
+ * Assume 20 MHz channel for now.
+ * TODO: Use the secondary channel and VHT channel width that will be
+ * used after association.
+ */
+ if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+ &current, &chan) == NUM_HOSTAPD_MODES)
+ return 0;
+
+ /*
+ * Need 3 bytes for EID, length, and current operating class, plus
+ * 1 byte for every other supported operating class.
+ */
+ buf = wpabuf_alloc(global_op_class_size + 3);
+ if (!buf)
+ return 0;
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
+ /* Will set the length later, putting a placeholder */
+ ie_len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, current);
+
+ for (op = 0; global_op_class[op].op_class; op++) {
+ if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
+ wpabuf_put_u8(buf, global_op_class[op].op_class);
+ }
+
+ *ie_len = wpabuf_len(buf) - 2;
+ if (*ie_len < 2 || wpabuf_len(buf) > len) {
+ wpa_printf(MSG_ERROR,
+ "Failed to add supported operating classes IE");
+ res = 0;
+ } else {
+ os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
+ res = wpabuf_len(buf);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "MBO: Added supported operating classes IE",
+ buf);
+ }
+
+ wpabuf_free(buf);
+ return res;
+}
+
+
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
+ size_t len)
+{
+ const u8 *pos, *cell_pref = NULL, *reason = NULL;
+ u8 id, elen;
+ u16 disallowed_sec = 0;
+
+ if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
+ mbo_ie[3] != MBO_OUI_TYPE)
+ return;
+
+ pos = mbo_ie + 4;
+ len -= 4;
+
+ while (len >= 2) {
+ id = *pos++;
+ elen = *pos++;
+ len -= 2;
+
+ if (elen > len)
+ goto fail;
+
+ switch (id) {
+ case MBO_ATTR_ID_CELL_DATA_PREF:
+ if (elen != 1)
+ goto fail;
+
+ if (wpa_s->conf->mbo_cell_capa ==
+ MBO_CELL_CAPA_AVAILABLE)
+ cell_pref = pos;
+ else
+ wpa_printf(MSG_DEBUG,
+ "MBO: Station does not support Cellular data connection");
+ break;
+ case MBO_ATTR_ID_TRANSITION_REASON:
+ if (elen != 1)
+ goto fail;
+
+ reason = pos;
+ break;
+ case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
+ if (elen != 2)
+ goto fail;
+
+ if (wpa_s->wnm_mode &
+ WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Unexpected association retry delay, BSS is terminating");
+ goto fail;
+ } else if (wpa_s->wnm_mode &
+ WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ disallowed_sec = WPA_GET_LE16(pos);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Association retry delay attribute not in disassoc imminent mode");
+ }
+
+ break;
+ case MBO_ATTR_ID_AP_CAPA_IND:
+ case MBO_ATTR_ID_NON_PREF_CHAN_REPORT:
+ case MBO_ATTR_ID_CELL_DATA_CAPA:
+ case MBO_ATTR_ID_ASSOC_DISALLOW:
+ case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
+ wpa_printf(MSG_DEBUG,
+ "MBO: Attribute %d should not be included in BTM Request frame",
+ id);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
+ id);
+ return;
+ }
+
+ pos += elen;
+ len -= elen;
+ }
+
+ if (cell_pref)
+ wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
+ *cell_pref);
+
+ if (reason)
+ wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
+ *reason);
+
+ if (disallowed_sec && wpa_s->current_bss)
+ wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
+ disallowed_sec);
+
+ return;
+fail:
+ wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)",
+ id, elen, len);
+}
+
+
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+ size_t len,
+ enum mbo_transition_reject_reason reason)
+{
+ u8 reject_attr[3];
+
+ reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON;
+ reject_attr[1] = 1;
+ reject_attr[2] = reason;
+
+ return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr));
+}
+
+
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa)
+{
+ u8 cell_capa[7];
+
+ if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Cellular capability already set to %u",
+ mbo_cell_capa);
+ return;
+ }
+
+ wpa_s->conf->mbo_cell_capa = mbo_cell_capa;
+
+ cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC;
+ cell_capa[1] = 5; /* Length */
+ WPA_PUT_BE24(cell_capa + 2, OUI_WFA);
+ cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA;
+ cell_capa[6] = mbo_cell_capa;
+
+ wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+}
+
+
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+ struct wpabuf *anqp_buf;
+ u8 *len_pos;
+
+ if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+ wpa_printf(MSG_INFO, "MBO: " MACSTR
+ " does not support MBO - cannot request MBO ANQP elements from it",
+ MAC2STR(bss->bssid));
+ return NULL;
+ }
+
+ anqp_buf = wpabuf_alloc(10);
+ if (!anqp_buf)
+ return NULL;
+
+ len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(anqp_buf, OUI_WFA);
+ wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE);
+
+ wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
+ gas_anqp_set_element_len(anqp_buf, len_pos);
+
+ return anqp_buf;
+}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 77f708b..d67d3b2 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -66,9 +66,11 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
}
-static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct mesh_conf *conf;
+ int cipher;
conf = os_zalloc(sizeof(struct mesh_conf));
if (!conf)
@@ -82,6 +84,33 @@ static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
+ conf->ieee80211w = ssid->ieee80211w;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+ if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
+ conf->ieee80211w = wpa_s->conf->pmf;
+ else
+ conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
+ }
+
+ cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
+ if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
+ wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
+ os_free(conf);
+ return NULL;
+ }
+ conf->pairwise_cipher = cipher;
+
+ cipher = wpa_pick_group_cipher(ssid->group_cipher);
+ if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
+ cipher == WPA_CIPHER_GTK_NOT_USED) {
+ wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
+ os_free(conf);
+ return NULL;
+ }
+
+ conf->group_cipher = cipher;
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
/* defaults */
conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -149,6 +178,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
if (!bss)
goto out_free;
+ dl_list_init(&bss->nr_db);
os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
bss->driver = wpa_s->driver;
@@ -175,24 +205,41 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
wpa_s->conf->dot11RSNASAERetransPeriod;
os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
- mconf = mesh_config_create(ssid);
+ mconf = mesh_config_create(wpa_s, ssid);
if (!mconf)
goto out_free;
ifmsh->mconf = mconf;
/* need conf->hw_mode for supported rates. */
- if (ssid->frequency == 0) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = 1;
- } else {
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- }
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel);
if (conf->hw_mode == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
ssid->frequency);
goto out_free;
}
+ if (ssid->ht40)
+ conf->secondary_channel = ssid->ht40;
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
+ conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ switch (conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ case VHT_CHANWIDTH_80P80MHZ:
+ ieee80211_freq_to_chan(
+ ssid->frequency,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ ieee80211_freq_to_chan(
+ ssid->frequency,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
+ conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
+ break;
+ }
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &conf->vht_oper_centr_freq_seg1_idx);
+ }
if (ssid->mesh_basic_rates == NULL) {
/*
@@ -318,16 +365,47 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
wpa_supplicant_mesh_deinit(wpa_s);
+ wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+ wpa_s->group_cipher = WPA_CIPHER_NONE;
+ wpa_s->mgmt_group_cipher = 0;
+
os_memset(&params, 0, sizeof(params));
params.meshid = ssid->ssid;
params.meshid_len = ssid->ssid_len;
ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
+ wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled;
+ if (params.freq.ht_enabled && params.freq.sec_channel_offset)
+ ssid->ht40 = params.freq.sec_channel_offset;
+ if (wpa_s->mesh_vht_enabled) {
+ ssid->vht = 1;
+ switch (params.freq.bandwidth) {
+ case 80:
+ if (params.freq.center_freq2) {
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ ssid->vht_center_freq2 =
+ params.freq.center_freq2;
+ } else {
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ }
+ break;
+ case 160:
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+ }
if (ssid->beacon_int > 0)
params.beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
params.beacon_int = wpa_s->conf->beacon_int;
- params.max_peer_links = wpa_s->conf->max_peer_links;
+ if (ssid->dtim_period > 0)
+ params.dtim_period = ssid->dtim_period;
+ else if (wpa_s->conf->dtim_period > 0)
+ params.dtim_period = wpa_s->conf->dtim_period;
+ params.conf.max_peer_links = wpa_s->conf->max_peer_links;
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
@@ -337,10 +415,10 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
if (wpa_s->conf->user_mpm) {
params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
- params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params.conf.auto_plinks = 0;
} else {
params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params.conf.auto_plinks = 1;
}
params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
@@ -351,21 +429,32 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
goto out;
}
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
+ wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
+ wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
+ }
+
if (wpa_s->ifmsh) {
params.ies = wpa_s->ifmsh->mconf->rsn_ie;
params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
params.basic_rates = wpa_s->ifmsh->basic_rates;
+ params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
}
wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
ret = wpa_drv_join_mesh(wpa_s, &params);
if (ret)
- wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
+ wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
/* hostapd sets the interface down until we associate */
wpa_drv_set_operstate(wpa_s, 1);
+ if (!ret)
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
out:
return ret;
}
@@ -535,9 +624,22 @@ int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
if (!mesh_wpa_s) {
wpa_printf(MSG_ERROR,
"mesh: Failed to create new wpa_supplicant interface");
- wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
return -1;
}
mesh_wpa_s->mesh_if_created = 1;
return 0;
}
+
+
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ return mesh_mpm_close_peer(wpa_s, addr);
+}
+
+
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
+{
+ return mesh_mpm_connect_peer(wpa_s, addr, duration);
+}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
index 3cb7f1b..7317083 100644
--- a/wpa_supplicant/mesh.h
+++ b/wpa_supplicant/mesh.h
@@ -18,6 +18,9 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
char *end);
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
size_t len);
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index f81b88c..d14c7e3 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -14,17 +14,18 @@
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "mesh_mpm.h"
#include "mesh_rsn.h"
struct mesh_peer_mgmt_ie {
- const u8 *proto_id;
- const u8 *llid;
- const u8 *plid;
- const u8 *reason;
- const u8 *pmk;
+ const u8 *proto_id; /* Mesh Peering Protocol Identifier (2 octets) */
+ const u8 *llid; /* Local Link ID (2 octets) */
+ const u8 *plid; /* Peer Link ID (conditional, 2 octets) */
+ const u8 *reason; /* Reason Code (conditional, 2 octets) */
+ const u8 *chosen_pmk; /* Chosen PMK (optional, 16 octets) */
};
static void plink_timer(void *eloop_ctx, void *user_data);
@@ -34,18 +35,17 @@ enum plink_event {
PLINK_UNDEFINED,
OPN_ACPT,
OPN_RJCT,
- OPN_IGNR,
CNF_ACPT,
CNF_RJCT,
- CNF_IGNR,
CLS_ACPT,
- CLS_IGNR
+ REQ_RJCT
};
static const char * const mplstate[] = {
- [PLINK_LISTEN] = "LISTEN",
- [PLINK_OPEN_SENT] = "OPEN_SENT",
- [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [0] = "UNINITIALIZED",
+ [PLINK_IDLE] = "IDLE",
+ [PLINK_OPN_SNT] = "OPN_SNT",
+ [PLINK_OPN_RCVD] = "OPN_RCVD",
[PLINK_CNF_RCVD] = "CNF_RCVD",
[PLINK_ESTAB] = "ESTAB",
[PLINK_HOLDING] = "HOLDING",
@@ -56,12 +56,10 @@ static const char * const mplevent[] = {
[PLINK_UNDEFINED] = "UNDEFINED",
[OPN_ACPT] = "OPN_ACPT",
[OPN_RJCT] = "OPN_RJCT",
- [OPN_IGNR] = "OPN_IGNR",
[CNF_ACPT] = "CNF_ACPT",
[CNF_RJCT] = "CNF_RJCT",
- [CNF_IGNR] = "CNF_IGNR",
[CLS_ACPT] = "CLS_ACPT",
- [CLS_IGNR] = "CLS_IGNR"
+ [REQ_RJCT] = "REQ_RJCT",
};
@@ -72,10 +70,10 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
{
os_memset(mpm_ie, 0, sizeof(*mpm_ie));
- /* remove optional PMK at end */
- if (len >= 16) {
- len -= 16;
- mpm_ie->pmk = ie + len - 16;
+ /* Remove optional Chosen PMK field at end */
+ if (len >= SAE_PMKID_LEN) {
+ mpm_ie->chosen_pmk = ie + len - SAE_PMKID_LEN;
+ len -= SAE_PMKID_LEN;
}
if ((action_field == PLINK_OPEN && len != 4) ||
@@ -101,8 +99,8 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
len -= 2;
}
- /* plid, present for confirm, and possibly close */
- if (len)
+ /* Peer Link ID, present for confirm, and possibly close */
+ if (len >= 2)
mpm_ie->plid = ie;
return 0;
@@ -193,12 +191,13 @@ static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
sta->my_lid = llid;
sta->peer_lid = 0;
+ sta->peer_aid = 0;
/*
* We do not use wpa_mesh_set_plink_state() here because there is no
* entry in kernel yet.
*/
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = PLINK_IDLE;
}
@@ -212,9 +211,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
struct hostapd_data *bss = ifmsh->bss[0];
struct mesh_conf *conf = ifmsh->mconf;
u8 supp_rates[2 + 2 + 32];
-#ifdef CONFIG_IEEE80211N
- u8 ht_capa_oper[2 + 26 + 2 + 22];
-#endif /* CONFIG_IEEE80211N */
u8 *pos, *cat;
u8 ie_len, add_plid = 0;
int ret;
@@ -239,6 +235,12 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
2 + 22; /* HT operation */
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
+ buf_len += 2 + 12 + /* VHT Capabilities */
+ 2 + 5; /* VHT Operation */
+ }
+#endif /* CONFIG_IEEE80211AC */
if (type != PLINK_CLOSE)
buf_len += conf->rsn_ie_len; /* RSN IE */
@@ -258,7 +260,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
/* aid */
if (type == PLINK_CONFIRM)
- wpabuf_put_le16(buf, sta->peer_lid);
+ wpabuf_put_le16(buf, sta->aid);
/* IE: supp + ext. supp rates */
pos = hostapd_eid_supp_rates(bss, supp_rates);
@@ -285,7 +287,8 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
/* TODO: Add Connected to Mesh Gate/AS subfields */
wpabuf_put_u8(buf, info);
/* always forwarding & accepting plinks for now */
- wpabuf_put_u8(buf, 0x1 | 0x8);
+ wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
+ MESH_CAP_FORWARDING);
} else { /* Peer closing frame */
/* IE: Mesh ID */
wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
@@ -334,11 +337,22 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+ u8 ht_capa_oper[2 + 26 + 2 + 22];
+
pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
pos = hostapd_eid_ht_operation(bss, pos);
wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
+ u8 vht_capa_oper[2 + 12 + 2 + 5];
+
+ pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper, 0);
+ pos = hostapd_eid_vht_operation(bss, pos);
+ wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
+ }
+#endif /* CONFIG_IEEE80211AC */
if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
wpa_msg(wpa_s, MSG_INFO,
@@ -346,6 +360,9 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
goto fail;
}
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh MPM: Sending peering frame type %d to "
+ MACSTR " (my_lid=0x%x peer_lid=0x%x)",
+ type, MAC2STR(sta->addr), sta->my_lid, sta->peer_lid);
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
sta->addr, wpa_s->own_addr, wpa_s->own_addr,
wpabuf_head(buf), wpabuf_len(buf), 0);
@@ -366,15 +383,17 @@ void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
struct hostapd_sta_add_params params;
int ret;
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " from %s into %s",
+ MAC2STR(sta->addr), mplstate[sta->plink_state],
+ mplstate[state]);
sta->plink_state = state;
os_memset(&params, 0, sizeof(params));
params.addr = sta->addr;
params.plink_state = state;
+ params.peer_aid = sta->peer_aid;
params.set = 1;
- wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
- MAC2STR(sta->addr), mplstate[state]);
ret = wpa_drv_sta_add(wpa_s, &params);
if (ret) {
wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
@@ -400,10 +419,11 @@ static void plink_timer(void *eloop_ctx, void *user_data)
struct sta_info *sta = user_data;
u16 reason = 0;
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
- case PLINK_OPEN_RCVD:
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_RCVD:
+ case PLINK_OPN_SNT:
/* retry timer */
if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
eloop_register_timeout(
@@ -429,6 +449,13 @@ static void plink_timer(void *eloop_ctx, void *user_data)
break;
case PLINK_HOLDING:
/* holding timer */
+
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR
+ " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ }
mesh_mpm_fsm_restart(wpa_s, sta);
break;
default:
@@ -453,8 +480,8 @@ mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
}
-int mesh_mpm_plink_close(struct hostapd_data *hapd,
- struct sta_info *sta, void *ctx)
+static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
+ void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
@@ -472,6 +499,85 @@ int mesh_mpm_plink_close(struct hostapd_data *hapd,
}
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+
+ if (!wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+ return -1;
+ }
+
+ hapd = wpa_s->ifmsh->bss[0];
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+ return -1;
+ }
+
+ return mesh_mpm_plink_close(hapd, sta, wpa_s) == 0 ? 0 : -1;
+}
+
+
+static void peer_add_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ os_memset(hapd->mesh_required_peer, 0, ETH_ALEN);
+}
+
+
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ struct mesh_conf *conf;
+
+ if (!wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+ return -1;
+ }
+
+ if (!ssid || !ssid->no_auto_peer) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "This command is available only with no_auto_peer mesh network");
+ return -1;
+ }
+
+ hapd = wpa_s->ifmsh->bss[0];
+ conf = wpa_s->ifmsh->mconf;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+ return -1;
+ }
+
+ if ((PLINK_OPN_SNT <= sta->plink_state &&
+ sta->plink_state <= PLINK_ESTAB) ||
+ (sta->sae && sta->sae->state > SAE_NOTHING)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Specified peer is connecting/connected");
+ return -1;
+ }
+
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
+ } else {
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
+ eloop_register_timeout(duration == -1 ? 10 : duration, 0,
+ peer_add_timer, wpa_s, NULL);
+ }
+
+ return 0;
+}
+
+
void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
{
struct hostapd_data *hapd = ifmsh->bss[0];
@@ -481,6 +587,7 @@ void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
hapd->num_plinks = 0;
hostapd_free_stas(hapd);
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
}
@@ -522,7 +629,7 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
}
/*
@@ -541,6 +648,14 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
struct sta_info *sta;
int ret;
+ if (elems->mesh_config_len >= 7 &&
+ !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "mesh: Ignore a crowded peer " MACSTR,
+ MAC2STR(addr));
+ return NULL;
+ }
+
sta = ap_get_sta(data, addr);
if (!sta) {
sta = ap_sta_add(data, addr);
@@ -548,28 +663,45 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
return NULL;
}
+ /* Set WMM by default since Mesh STAs are QoS STAs */
+ sta->flags |= WLAN_STA_WMM;
+
/* initialize sta */
if (copy_supp_rates(wpa_s, sta, elems)) {
ap_free_sta(data, sta);
return NULL;
}
- mesh_mpm_init_link(wpa_s, sta);
+ if (!sta->my_lid)
+ mesh_mpm_init_link(wpa_s, sta);
#ifdef CONFIG_IEEE80211N
copy_sta_ht_capab(data, sta, elems->ht_capabilities);
update_ht_state(data, sta);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ copy_sta_vht_capab(data, sta, elems->vht_capabilities);
+ set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
+#endif /* CONFIG_IEEE80211AC */
+
+ if (hostapd_get_aid(data, sta) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "No AIDs available");
+ ap_free_sta(data, sta);
+ return NULL;
+ }
+
/* insert into driver */
os_memset(&params, 0, sizeof(params));
params.supp_rates = sta->supported_rates;
params.supp_rates_len = sta->supported_rates_len;
params.addr = addr;
params.plink_state = sta->plink_state;
- params.aid = sta->peer_lid;
+ params.aid = sta->aid;
+ params.peer_aid = sta->peer_aid;
params.listen_interval = 100;
params.ht_capabilities = sta->ht_capabilities;
+ params.vht_capabilities = sta->vht_capabilities;
params.flags |= WPA_STA_WMM;
params.flags_mask |= WPA_STA_AUTHENTICATED;
if (conf->security == MESH_CONF_SEC_NONE) {
@@ -605,7 +737,9 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
if (!sta)
return;
- if (ssid && ssid->no_auto_peer) {
+ if (ssid && ssid->no_auto_peer &&
+ (is_zero_ether_addr(data->mesh_required_peer) ||
+ os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) {
wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
MACSTR " because of no_auto_peer", MAC2STR(addr));
if (data->mesh_pending_auth) {
@@ -634,10 +768,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
return;
}
- if (conf->security == MESH_CONF_SEC_NONE)
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
- else
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ if (sta->plink_state < PLINK_OPN_SNT ||
+ sta->plink_state > PLINK_ESTAB)
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
+ } else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
+ }
}
@@ -664,64 +801,85 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
MAC2STR(sta->addr));
if (conf->security & MESH_CONF_SEC_AMPE) {
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
- seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
-
- wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
- wpa_hexdump_key(MSG_DEBUG, "mgtk:",
- sta->mgtk, sizeof(sta->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
+ sta->addr, 0, 0, seq, sizeof(seq),
+ sta->mtk, sta->mtk_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
+ sta->mgtk, sta->mgtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
+ sta->addr, sta->mgtk_key_id, 0,
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
+ sta->mgtk, sta->mgtk_len);
+
+ if (sta->igtk_len) {
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
+ sta->igtk, sta->igtk_len);
+ wpa_drv_set_key(
+ wpa_s,
+ wpa_cipher_to_alg(conf->mgmt_group_cipher),
+ sta->addr, sta->igtk_key_id, 0,
+ sta->igtk_rsc, sizeof(sta->igtk_rsc),
+ sta->igtk, sta->igtk_len);
+ }
}
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
hapd->num_plinks++;
sta->flags |= WLAN_STA_ASSOC;
+ sta->mesh_sae_pmksa_caching = 0;
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
+ peer_add_timer(wpa_s, NULL);
eloop_cancel_timeout(plink_timer, wpa_s, sta);
/* Send ctrl event */
- wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
- MAC2STR(sta->addr));
+ wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
+ MAC2STR(sta->addr));
}
static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
- enum plink_event event)
+ enum plink_event event, u16 reason)
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
- u16 reason = 0;
wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
MAC2STR(sta->addr), mplstate[sta->plink_state],
mplevent[event]);
switch (sta->plink_state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
switch (event) {
case CLS_ACPT:
mesh_mpm_fsm_restart(wpa_s, sta);
break;
case OPN_ACPT:
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
0);
break;
+ case REQ_RJCT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
default:
break;
}
break;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -736,12 +894,13 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
break;
case OPN_ACPT:
/* retry timer is left untouched */
- wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
break;
case CNF_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
eloop_register_timeout(
conf->dot11MeshConfirmTimeout / 1000,
(conf->dot11MeshConfirmTimeout % 1000) * 1000,
@@ -751,11 +910,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
break;
}
break;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -786,7 +946,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -801,6 +962,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
PLINK_CLOSE, reason);
break;
case OPN_ACPT:
+ if (conf->security & MESH_CONF_SEC_AMPE)
+ mesh_rsn_derive_mtk(wpa_s, sta);
mesh_mpm_plink_estab(wpa_s, sta);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
@@ -811,9 +974,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
break;
case PLINK_ESTAB:
switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
- reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
eloop_register_timeout(
conf->dot11MeshHoldingTimeout / 1000,
@@ -825,9 +991,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
" closed with reason %d",
MAC2STR(sta->addr), reason);
- wpa_msg_ctrl(wpa_s, MSG_INFO,
- MESH_PEER_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
+ wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR,
+ MAC2STR(sta->addr));
hapd->num_plinks--;
@@ -875,13 +1040,14 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
struct sta_info *sta;
- u16 plid = 0, llid = 0;
+ u16 plid = 0, llid = 0, aid = 0;
enum plink_event event;
struct ieee802_11_elems elems;
struct mesh_peer_mgmt_ie peer_mgmt_ie;
const u8 *ies;
size_t ie_len;
int ret;
+ u16 reason = 0;
if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
return;
@@ -912,7 +1078,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
ie_len -= 2;
}
if (action_field == PLINK_CONFIRM) {
- wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ aid = WPA_GET_LE16(ies);
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid);
ies += 2; /* aid */
ie_len -= 2;
}
@@ -956,6 +1123,10 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
llid = WPA_GET_LE16(peer_mgmt_ie.plid);
wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+ if (action_field == PLINK_CLOSE)
+ wpa_printf(MSG_DEBUG, "MPM: close reason=%u",
+ WPA_GET_LE16(peer_mgmt_ie.reason));
+
sta = ap_get_sta(hapd, mgmt->sa);
/*
@@ -963,7 +1134,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
* open mesh, then go ahead and add the peer before proceeding.
*/
if (!sta && action_field == PLINK_OPEN &&
- !(mconf->security & MESH_CONF_SEC_AMPE))
+ (!(mconf->security & MESH_CONF_SEC_AMPE) ||
+ wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa)))
sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
if (!sta) {
@@ -982,12 +1154,24 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- if ((mconf->security & MESH_CONF_SEC_AMPE) &&
- mesh_rsn_process_ampe(wpa_s, sta, &elems,
- &mgmt->u.action.category,
- ies, ie_len)) {
- wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
- return;
+ if (mconf->security & MESH_CONF_SEC_AMPE) {
+ int res;
+
+ res = mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ peer_mgmt_ie.chosen_pmk,
+ ies, ie_len);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: RSN process rejected frame (res=%d)",
+ res);
+ if (action_field == PLINK_OPEN && res == -2) {
+ /* AES-SIV decryption failed */
+ mesh_mpm_fsm(wpa_s, sta, OPN_RJCT,
+ WLAN_REASON_MESH_INVALID_GTK);
+ }
+ return;
+ }
}
if (sta->plink_state == PLINK_BLOCKED) {
@@ -999,12 +1183,16 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
switch (action_field) {
case PLINK_OPEN:
if (plink_free_count(hapd) == 0) {
- event = OPN_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->peer_lid && sta->peer_lid != plid) {
- event = OPN_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
sta->peer_lid = plid;
event = OPN_ACPT;
@@ -1012,16 +1200,21 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
break;
case PLINK_CONFIRM:
if (plink_free_count(hapd) == 0) {
- event = CNF_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->my_lid != llid ||
(sta->peer_lid && sta->peer_lid != plid)) {
- event = CNF_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x",
+ sta->my_lid, llid, sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
if (!sta->peer_lid)
sta->peer_lid = plid;
+ sta->peer_aid = aid;
event = CNF_ACPT;
}
break;
@@ -1037,12 +1230,19 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
* restarted.
*/
event = CLS_ACPT;
- else if (sta->peer_lid != plid)
- event = CLS_IGNR;
- else if (peer_mgmt_ie.plid && sta->my_lid != llid)
- event = CLS_IGNR;
- else
+ else if (sta->peer_lid != plid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
+ } else if (peer_mgmt_ie.plid && sta->my_lid != llid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: my_lid mismatch: 0x%x != 0x%x",
+ sta->my_lid, llid);
+ return; /* no FSM event */
+ } else {
event = CLS_ACPT;
+ }
break;
default:
/*
@@ -1052,13 +1252,15 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
*/
return;
}
- mesh_mpm_fsm(wpa_s, sta, event);
+ mesh_mpm_fsm(wpa_s, sta, event, reason);
}
/* called by ap_free_sta */
-void mesh_mpm_free_sta(struct sta_info *sta)
+void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
+ if (sta->plink_state == PLINK_ESTAB)
+ hapd->num_plinks--;
eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
}
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index 7ebaef0..5fc1e61 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -14,10 +14,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
struct ieee802_11_elems *elems);
void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
-void mesh_mpm_free_sta(struct sta_info *sta);
+void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
struct sta_info *sta,
enum mesh_plink_state state);
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 747f1ae..27ab8cb 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -27,12 +27,12 @@
#define MESH_AUTH_TIMEOUT 10
#define MESH_AUTH_RETRY 3
-#define MESH_AUTH_BLOCK_DURATION 3600
void mesh_auth_timer(void *eloop_ctx, void *user_data)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct sta_info *sta = user_data;
+ struct hostapd_data *hapd;
if (sta->sae->state != SAE_ACCEPTED) {
wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
@@ -43,23 +43,20 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data)
if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
mesh_rsn_auth_sae_sta(wpa_s, sta);
} else {
+ hapd = wpa_s->ifmsh->bss[0];
+
if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
- ap_free_sta(wpa_s->ifmsh->bss[0], sta);
+ ap_free_sta(hapd, sta);
return;
}
/* block the STA if exceeded the number of attempts */
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
sta->sae->state = SAE_NOTHING;
- if (wpa_s->mesh_auth_block_duration <
- MESH_AUTH_BLOCK_DURATION)
- wpa_s->mesh_auth_block_duration += 60;
- eloop_register_timeout(wpa_s->mesh_auth_block_duration,
- 0, mesh_auth_timer, wpa_s, sta);
wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
MACSTR " duration=%d",
MAC2STR(sta->addr),
- wpa_s->mesh_auth_block_duration);
+ hapd->conf->ap_max_inactivity);
}
sta->sae_auth_retry++;
}
@@ -139,7 +136,8 @@ static int auth_start_ampe(void *ctx, const u8 *addr)
}
-static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
+ enum mfp_options ieee80211w)
{
struct wpa_auth_config conf;
struct wpa_auth_callbacks cb;
@@ -148,13 +146,18 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
os_memset(&conf, 0, sizeof(conf));
- conf.wpa = 2;
+ conf.wpa = WPA_PROTO_RSN;
conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.wpa_pairwise = rsn->pairwise_cipher;
+ conf.rsn_pairwise = rsn->pairwise_cipher;
+ conf.wpa_group = rsn->group_cipher;
conf.eapol_version = 0;
conf.wpa_group_rekey = -1;
+#ifdef CONFIG_IEEE80211W
+ conf.ieee80211w = ieee80211w;
+ if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
os_memset(&cb, 0, sizeof(cb));
cb.ctx = rsn;
@@ -170,18 +173,34 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
}
/* TODO: support rekeying */
- if (random_get_bytes(rsn->mgtk, 16) < 0) {
- wpa_deinit(rsn->auth);
+ rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group);
+ if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0)
return -1;
- }
+ rsn->mgtk_key_id = 1;
- /* group mgmt */
- wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
- seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+#ifdef CONFIG_IEEE80211W
+ if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
+ if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
+ return -1;
+ rsn->igtk_key_id = 4;
+
+ /* group mgmt */
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
+ rsn->igtk, rsn->igtk_len);
+ wpa_drv_set_key(rsn->wpa_s,
+ wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+ rsn->igtk_key_id, 1,
+ seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
- wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
- seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
+ rsn->mgtk, rsn->mgtk_len);
+ wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+ rsn->mgtk_key_id, 1, seq, sizeof(seq),
+ rsn->mgtk, rsn->mgtk_len);
return 0;
}
@@ -190,6 +209,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
static void mesh_rsn_deinit(struct mesh_rsn *rsn)
{
os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ rsn->mgtk_len = 0;
+ os_memset(rsn->igtk, 0, sizeof(rsn->igtk));
+ rsn->igtk_len = 0;
if (rsn->auth)
wpa_deinit(rsn->auth);
}
@@ -207,8 +229,12 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
if (mesh_rsn == NULL)
return NULL;
mesh_rsn->wpa_s = wpa_s;
+ mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
+ mesh_rsn->group_cipher = conf->group_cipher;
+ mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
- if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+ if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
+ conf->ieee80211w) < 0) {
mesh_rsn_deinit(mesh_rsn);
os_free(mesh_rsn);
return NULL;
@@ -291,6 +317,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct rsn_pmksa_cache_entry *pmksa;
unsigned int rnd;
int ret;
@@ -306,6 +333,29 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
return -1;
}
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
+ if (pmksa) {
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to initialize RSN state machine");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "AUTH: Mesh PMKSA cache entry found for " MACSTR
+ " - try to use PMKSA caching instead of new SAE authentication",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
+ sta->sae->pmkid, sta->sae->pmk);
+ sae_accept_sta(hapd, sta);
+ sta->mesh_sae_pmksa_caching = 1;
+ return 0;
+ }
+ sta->mesh_sae_pmksa_caching = 0;
+
if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
return -1;
@@ -313,7 +363,6 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
"AUTH: started authentication with SAE peer: " MACSTR,
MAC2STR(sta->addr));
- wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
ret = auth_sae_init_committed(hapd, sta);
if (ret)
return ret;
@@ -328,10 +377,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
{
- /* don't expect wpa auth to cache the pmkid for now */
- rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr,
- sta->addr, pmkid,
- wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm)));
+ os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN);
}
@@ -340,18 +386,27 @@ mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
{
u8 *myaddr = rsn->wpa_s->own_addr;
u8 *peer = sta->addr;
- u8 *addr1 = peer, *addr2 = myaddr;
- u8 context[AES_BLOCK_SIZE];
+ u8 *addr1, *addr2;
+ u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context;
- /* SAE */
- RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+ /*
+ * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite ||
+ * min(localMAC, peerMAC) || max(localMAC, peerMAC))
+ */
+ /* Selected AKM Suite: SAE */
+ RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+ ptr += RSN_SELECTOR_LEN;
if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
addr1 = myaddr;
addr2 = peer;
+ } else {
+ addr1 = peer;
+ addr2 = myaddr;
}
- os_memcpy(context + 4, addr1, ETH_ALEN);
- os_memcpy(context + 10, addr2, ETH_ALEN);
+ os_memcpy(ptr, addr1, ETH_ALEN);
+ ptr += ETH_ALEN;
+ os_memcpy(ptr, addr2, ETH_ALEN);
sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
context, sizeof(context), sta->aek, sizeof(sta->aek));
@@ -363,40 +418,44 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
{
u8 *ptr;
u8 *min, *max;
- u16 min_lid, max_lid;
- size_t nonce_len = sizeof(sta->my_nonce);
- size_t lid_len = sizeof(sta->my_lid);
u8 *myaddr = wpa_s->own_addr;
u8 *peer = sta->addr;
- /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
- u8 context[64 + 4 + 4 + 12];
-
+ u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN];
+
+ /*
+ * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce,
+ * peerNonce) || max(localNonce, peerNonce) || min(localLinkID,
+ * peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite ||
+ * min(localMAC, peerMAC) || max(localMAC, peerMAC))
+ */
ptr = context;
- if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+ if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) {
min = sta->my_nonce;
max = sta->peer_nonce;
} else {
min = sta->peer_nonce;
max = sta->my_nonce;
}
- os_memcpy(ptr, min, nonce_len);
- os_memcpy(ptr + nonce_len, max, nonce_len);
- ptr += 2 * nonce_len;
+ os_memcpy(ptr, min, WPA_NONCE_LEN);
+ ptr += WPA_NONCE_LEN;
+ os_memcpy(ptr, max, WPA_NONCE_LEN);
+ ptr += WPA_NONCE_LEN;
if (sta->my_lid < sta->peer_lid) {
- min_lid = host_to_le16(sta->my_lid);
- max_lid = host_to_le16(sta->peer_lid);
+ WPA_PUT_LE16(ptr, sta->my_lid);
+ ptr += 2;
+ WPA_PUT_LE16(ptr, sta->peer_lid);
+ ptr += 2;
} else {
- min_lid = host_to_le16(sta->peer_lid);
- max_lid = host_to_le16(sta->my_lid);
+ WPA_PUT_LE16(ptr, sta->peer_lid);
+ ptr += 2;
+ WPA_PUT_LE16(ptr, sta->my_lid);
+ ptr += 2;
}
- os_memcpy(ptr, &min_lid, lid_len);
- os_memcpy(ptr + lid_len, &max_lid, lid_len);
- ptr += 2 * lid_len;
- /* SAE */
- RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
- ptr += 4;
+ /* Selected AKM Suite: SAE */
+ RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+ ptr += RSN_SELECTOR_LEN;
if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
min = myaddr;
@@ -406,22 +465,24 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
max = myaddr;
}
os_memcpy(ptr, min, ETH_ALEN);
- os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+ ptr += ETH_ALEN;
+ os_memcpy(ptr, max, ETH_ALEN);
- sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+ sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher);
+ sha256_prf(sta->sae->pmk, SAE_PMK_LEN,
"Temporal Key Derivation", context, sizeof(context),
- sta->mtk, sizeof(sta->mtk));
+ sta->mtk, sta->mtk_len);
return 0;
}
void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
{
- if (random_get_bytes(sta->my_nonce, 32) < 0) {
+ if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) {
wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
/* TODO: How to handle this more cleanly? */
}
- os_memset(sta->peer_nonce, 0, 32);
+ os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN);
mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
}
@@ -437,65 +498,94 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
{
struct ieee80211_ampe_ie *ampe;
u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
- u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+ u8 *ampe_ie, *pos, *mic_payload;
const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
int ret = 0;
+ size_t len;
+
+ len = sizeof(*ampe);
+ if (cat[1] == PLINK_OPEN)
+ len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
+#ifdef CONFIG_IEEE80211W
+ if (cat[1] == PLINK_OPEN && rsn->igtk_len)
+ len += 2 + 6 + rsn->igtk_len;
+#endif /* CONFIG_IEEE80211W */
- if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+ if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
return -EINVAL;
}
- ampe_ie = os_zalloc(2 + sizeof(*ampe));
+ ampe_ie = os_zalloc(2 + len);
if (!ampe_ie) {
wpa_printf(MSG_ERROR, "protect frame: out of memory");
return -ENOMEM;
}
- mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
- if (!mic_ie) {
- wpa_printf(MSG_ERROR, "protect frame: out of memory");
- ret = -ENOMEM;
- goto free;
- }
-
/* IE: AMPE */
ampe_ie[0] = WLAN_EID_AMPE;
- ampe_ie[1] = sizeof(*ampe);
+ ampe_ie[1] = len;
ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
- wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
- os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
- os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
- /* incomplete: see 13.5.4 */
+ RSN_CIPHER_SUITE_CCMP);
+ os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN);
+ os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
+
+ pos = (u8 *) (ampe + 1);
+ if (cat[1] != PLINK_OPEN)
+ goto skip_keys;
+
+ /* TODO: Key Replay Counter[8] optionally for
+ * Mesh Group Key Inform/Acknowledge frames */
+
/* TODO: static mgtk for now since we don't support rekeying! */
- os_memcpy(ampe->mgtk, rsn->mgtk, 16);
- /* TODO: Populate Key RSC */
- /* expire in 13 decades or so */
- os_memset(ampe->key_expiration, 0xff, 4);
+ /*
+ * GTKdata[variable]:
+ * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+ */
+ os_memcpy(pos, rsn->mgtk, rsn->mgtk_len);
+ pos += rsn->mgtk_len;
+ wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos);
+ pos += WPA_KEY_RSC_LEN;
+ /* Use fixed GTKExpirationTime for now */
+ WPA_PUT_LE32(pos, 0xffffffff);
+ pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+ /*
+ * IGTKdata[variable]:
+ * Key ID[2], IPN[6], IGTK[variable]
+ */
+ if (rsn->igtk_len) {
+ WPA_PUT_LE16(pos, rsn->igtk_key_id);
+ pos += 2;
+ wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos);
+ pos += 6;
+ os_memcpy(pos, rsn->igtk, rsn->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
+skip_keys:
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
+ ampe_ie, 2 + len);
/* IE: MIC */
- mic_ie[0] = WLAN_EID_MIC;
- mic_ie[1] = AES_BLOCK_SIZE;
- wpabuf_put_data(buf, mic_ie, 2);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, AES_BLOCK_SIZE);
/* MIC field is output ciphertext */
/* encrypt after MIC */
- mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
- AES_BLOCK_SIZE);
+ mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE);
- if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+ if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3,
aad, aad_len, mic_payload)) {
wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
ret = -ENOMEM;
- goto free;
}
-free:
os_free(ampe_ie);
- os_free(mic_ie);
return ret;
}
@@ -503,18 +593,37 @@ free:
int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *chosen_pmk,
const u8 *start, size_t elems_len)
{
int ret = 0;
struct ieee80211_ampe_ie *ampe;
- u8 null_nonce[32] = {};
+ u8 null_nonce[WPA_NONCE_LEN] = {};
u8 ampe_eid;
u8 ampe_ie_len;
- u8 *ampe_buf, *crypt = NULL;
+ u8 *ampe_buf, *crypt = NULL, *pos, *end;
size_t crypt_len;
const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
(elems->mic - 2) - cat };
+ size_t key_len;
+
+ if (!sta->sae) {
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
+ wpa_printf(MSG_INFO,
+ "Mesh RSN: SAE is not prepared yet");
+ return -1;
+ }
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ }
+
+ if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
+ return -1;
+ }
if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
@@ -526,7 +635,7 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
return -1;
crypt_len = elems_len - (elems->mic - start);
- if (crypt_len < 2) {
+ if (crypt_len < 2 + AES_BLOCK_SIZE) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
return -1;
}
@@ -544,14 +653,19 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
aad, aad_len, ampe_buf)) {
wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
- ret = -1;
+ ret = -2;
goto free;
}
+ crypt_len -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element",
+ ampe_buf, crypt_len);
+
ampe_eid = *ampe_buf++;
ampe_ie_len = *ampe_buf++;
if (ampe_eid != WLAN_EID_AMPE ||
+ (size_t) 2 + ampe_ie_len > crypt_len ||
ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
ret = -1;
@@ -559,17 +673,89 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
}
ampe = (struct ieee80211_ampe_ie *) ampe_buf;
- if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
- os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+ pos = (u8 *) (ampe + 1);
+ end = ampe_buf + ampe_ie_len;
+ if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 &&
+ os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
ret = -1;
goto free;
}
os_memcpy(sta->peer_nonce, ampe->local_nonce,
sizeof(ampe->local_nonce));
- os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
- /* todo parse mgtk expiration */
+ /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge
+ * frames */
+
+ /*
+ * GTKdata shall not be included in Mesh Peering Confirm. While the
+ * standard does not state the same about IGTKdata, that same constraint
+ * needs to apply for it. It makes no sense to include the keys in Mesh
+ * Peering Close frames either, so while the standard does not seem to
+ * have a shall statement for these, they are described without
+ * mentioning GTKdata.
+ *
+ * An earlier implementation used to add GTKdata to both Mesh Peering
+ * Open and Mesh Peering Confirm frames, so ignore the possibly present
+ * GTKdata frame without rejecting the frame as a backwards
+ * compatibility mechanism.
+ */
+ if (cat[1] != PLINK_OPEN) {
+ if (end > pos) {
+ wpa_hexdump_key(MSG_DEBUG,
+ "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close",
+ pos, end - pos);
+ }
+ goto free;
+ }
+
+ /*
+ * GTKdata[variable]:
+ * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+ */
+ sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */
+ key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher);
+ if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element");
+ ret = -1;
+ goto free;
+ }
+ sta->mgtk_len = key_len;
+ os_memcpy(sta->mgtk, pos, sta->mgtk_len);
+ wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK",
+ sta->mgtk, sta->mgtk_len);
+ pos += sta->mgtk_len;
+ wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC",
+ pos, WPA_KEY_RSC_LEN);
+ os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc));
+ pos += WPA_KEY_RSC_LEN;
+ wpa_printf(MSG_DEBUG,
+ "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds",
+ WPA_GET_LE32(pos));
+ pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+ /*
+ * IGTKdata[variable]:
+ * Key ID[2], IPN[6], IGTK[variable]
+ */
+ key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher);
+ if (end - pos >= (int) (2 + 6 + key_len)) {
+ sta->igtk_key_id = WPA_GET_LE16(pos);
+ wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u",
+ sta->igtk_key_id);
+ pos += 2;
+ os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc));
+ wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ pos += 6;
+ os_memcpy(sta->igtk, pos, key_len);
+ sta->igtk_len = key_len;
+ wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
+ sta->igtk, sta->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
free:
os_free(crypt);
return ret;
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index b1471b2..8775ced 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -12,7 +12,15 @@
struct mesh_rsn {
struct wpa_supplicant *wpa_s;
struct wpa_authenticator *auth;
- u8 mgtk[16];
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 mgtk_key_id;
+ unsigned int mgmt_group_cipher;
+ u8 igtk_key_id;
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
#ifdef CONFIG_SAE
struct wpabuf *sae_token;
int sae_group_index;
@@ -30,6 +38,7 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
const u8 *cat, struct wpabuf *buf);
int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *chosen_pmk,
const u8 *start, size_t elems_len);
void mesh_auth_timer(void *eloop_ctx, void *user_data);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 45d06bf..67e36ae 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -13,6 +13,7 @@
#include "config.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
+#include "binder/binder.h"
#include "dbus/dbus_common.h"
#include "dbus/dbus_old.h"
#include "dbus/dbus_new.h"
@@ -34,6 +35,12 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global)
}
#endif /* CONFIG_DBUS */
+#ifdef CONFIG_BINDER
+ global->binder = wpas_binder_init(global);
+ if (!global->binder)
+ return -1;
+#endif /* CONFIG_BINDER */
+
return 0;
}
@@ -44,6 +51,11 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
if (global->dbus)
wpas_dbus_deinit(global->dbus);
#endif /* CONFIG_DBUS */
+
+#ifdef CONFIG_BINDER
+ if (global->binder)
+ wpas_binder_deinit(global->binder);
+#endif /* CONFIG_BINDER */
}
@@ -128,6 +140,15 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
}
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
+}
+
+
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -647,13 +668,13 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int network_id,
+ struct wpa_ssid *ssid, int persistent,
int client)
{
/* Notify a group has been started */
wpas_dbus_register_p2p_group(wpa_s, ssid);
- wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+ wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent);
}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index d9f0f5a..8cce0f3 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -23,6 +23,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
enum wpa_states new_state,
enum wpa_states old_state);
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -112,7 +113,7 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
u16 config_methods,
unsigned int generated_pin);
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int network_id,
+ struct wpa_ssid *ssid, int persistent,
int client);
void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 63af83a..26d41a4 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -23,8 +23,29 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
{
struct wpa_supplicant *iface;
- if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+ if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) {
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent &&
+ wpa_s->parent->ap_iface &&
+ os_memcmp(wpa_s->parent->own_addr,
+ wpa_s->own_addr, ETH_ALEN) == 0 &&
+ wpabuf_len(wpa_s->pending_action_tx) >= 2 &&
+ *wpabuf_head_u8(wpa_s->pending_action_tx) !=
+ WLAN_ACTION_PUBLIC) {
+ /*
+ * When P2P Device interface has same MAC address as
+ * the GO interface, make sure non-Public Action frames
+ * are sent through the GO interface. The P2P Device
+ * interface can only send Public Action frames.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use GO interface %s instead of interface %s for Action TX",
+ wpa_s->parent->ifname, wpa_s->ifname);
+ return wpa_s->parent;
+ }
+#endif /* CONFIG_P2P */
return wpa_s;
+ }
/*
* Try to find a group interface that matches with the source address.
@@ -118,8 +139,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
}
wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
- MACSTR " using interface %s",
- MAC2STR(wpa_s->pending_action_dst), iface->ifname);
+ MACSTR " using interface %s (pending_action_tx=%p)",
+ MAC2STR(wpa_s->pending_action_dst), iface->ifname,
+ wpa_s->pending_action_tx);
res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
wpa_s->pending_action_dst,
wpa_s->pending_action_src,
@@ -183,8 +205,12 @@ void offchannel_send_action_tx_status(
return;
}
- wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
-
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Delete matching pending action frame (dst="
+ MACSTR " pending_action_tx=%p)", MAC2STR(dst),
+ wpa_s->pending_action_tx);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
@@ -250,8 +276,11 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
if (wpa_s->pending_action_tx) {
wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
- "frame TX to " MACSTR,
- MAC2STR(wpa_s->pending_action_dst));
+ "frame TX to " MACSTR " (pending_action_tx=%p)",
+ MAC2STR(wpa_s->pending_action_dst),
+ wpa_s->pending_action_tx);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
wpabuf_free(wpa_s->pending_action_tx);
}
wpa_s->pending_action_tx_done = 0;
@@ -268,6 +297,12 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
wpa_s->pending_action_freq = freq;
wpa_s->pending_action_no_cck = no_cck;
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Stored pending action frame (dst=" MACSTR
+ " pending_action_tx=%p)",
+ MAC2STR(dst), wpa_s->pending_action_tx);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
struct wpa_supplicant *iface;
@@ -428,6 +463,9 @@ const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
*/
void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Clear pending Action frame TX (pending_action_tx=%p",
+ wpa_s->pending_action_tx);
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 78bdd08..b1fdc28 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -53,6 +53,13 @@
*/
#define P2P_GO_FREQ_CHANGE_TIME 5
+/**
+ * Defines CSA parameters which are used when GO evacuates the no longer valid
+ * channel (and if the driver supports channel switch).
+ */
+#define P2P_GO_CSA_COUNT 7
+#define P2P_GO_CSA_BLOCK_TX 0
+
#ifndef P2P_MAX_CLIENT_IDLE
/*
* How many seconds to try to reconnect to the GO when connection in P2P client
@@ -117,6 +124,10 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
int go);
static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len);
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+ int *force_freq, int *pref_freq, int go,
+ unsigned int *pref_freq_list,
+ unsigned int *num_pref_freq);
static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len);
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
@@ -340,6 +351,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
size_t ielen;
u8 *n, i;
+ unsigned int bands;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -369,28 +381,6 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
if (wps_ie == NULL)
goto fail;
- ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
- if (ies == NULL) {
- wpabuf_free(wps_ie);
- goto fail;
- }
- wpabuf_put_buf(ies, wps_ie);
- wpabuf_free(wps_ie);
-
- p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
-
- params->p2p_probe = 1;
- n = os_malloc(wpabuf_len(ies));
- if (n == NULL) {
- wpabuf_free(ies);
- goto fail;
- }
- os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
- params->extra_ies = n;
- params->extra_ies_len = wpabuf_len(ies);
- wpabuf_free(ies);
-
switch (type) {
case P2P_SCAN_SOCIAL:
params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
@@ -431,6 +421,29 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
break;
}
+ ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+ if (ies == NULL) {
+ wpabuf_free(wps_ie);
+ goto fail;
+ }
+ wpabuf_put_buf(ies, wps_ie);
+ wpabuf_free(wps_ie);
+
+ bands = wpas_get_bands(wpa_s, params->freqs);
+ p2p_scan_ie(wpa_s->global->p2p, ies, dev_id, bands);
+
+ params->p2p_probe = 1;
+ n = os_malloc(wpabuf_len(ies));
+ if (n == NULL) {
+ wpabuf_free(ies);
+ goto fail;
+ }
+ os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
+ params->extra_ies = n;
+ params->extra_ies_len = wpabuf_len(ies);
+ wpabuf_free(ies);
+
radio_remove_works(wpa_s, "p2p-scan", 0);
if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
params) < 0)
@@ -538,27 +551,39 @@ static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s)
}
+static unsigned int p2p_is_active_persistent_group(struct wpa_supplicant *wpa_s)
+{
+ return !wpa_s->p2p_mgmt && wpa_s->current_ssid &&
+ !wpa_s->current_ssid->disabled &&
+ wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->p2p_persistent_group;
+}
+
+
+static unsigned int p2p_is_active_persistent_go(struct wpa_supplicant *wpa_s)
+{
+ return p2p_is_active_persistent_group(wpa_s) &&
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO;
+}
+
+
/* Find an interface for a P2P group where we are the GO */
static struct wpa_supplicant *
wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
{
struct wpa_supplicant *save = NULL;
- struct wpa_ssid *s;
if (!wpa_s)
return NULL;
for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- for (s = wpa_s->conf->ssid; s; s = s->next) {
- if (s->disabled || !s->p2p_group ||
- s->mode != WPAS_MODE_P2P_GO)
- continue;
+ if (!p2p_is_active_persistent_go(wpa_s))
+ continue;
- /* Prefer a group with connected clients */
- if (p2p_get_group_num_members(wpa_s->p2p_group))
- return wpa_s;
- save = wpa_s;
- }
+ /* Prefer a group with connected clients */
+ if (p2p_get_group_num_members(wpa_s->p2p_group))
+ return wpa_s;
+ save = wpa_s;
}
/* No group with connected clients, so pick the one without (if any) */
@@ -566,29 +591,23 @@ wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
}
-/* Find an active P2P group where we are the GO */
-static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
- u8 *bssid)
+static unsigned int p2p_is_active_persistent_cli(struct wpa_supplicant *wpa_s)
{
- struct wpa_ssid *s, *empty = NULL;
+ return p2p_is_active_persistent_group(wpa_s) &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
- if (!wpa_s)
- return 0;
+/* Find an interface for a P2P group where we are the P2P Client */
+static struct wpa_supplicant *
+wpas_p2p_get_cli_group(struct wpa_supplicant *wpa_s)
+{
for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- for (s = wpa_s->conf->ssid; s; s = s->next) {
- if (s->disabled || !s->p2p_group ||
- s->mode != WPAS_MODE_P2P_GO)
- continue;
-
- os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN);
- if (p2p_get_group_num_members(wpa_s->p2p_group))
- return s;
- empty = s;
- }
+ if (p2p_is_active_persistent_cli(wpa_s))
+ return wpa_s;
}
- return empty;
+ return NULL;
}
@@ -607,20 +626,34 @@ wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
}
-static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role,
+ unsigned int *force_freq,
+ unsigned int *pref_freq)
{
- struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+ struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
u8 conncap = P2PS_SETUP_NONE;
unsigned int owned_members = 0;
- unsigned int owner = 0;
- unsigned int client = 0;
- struct wpa_supplicant *go_wpa_s;
+ struct wpa_supplicant *go_wpa_s, *cli_wpa_s;
struct wpa_ssid *persistent_go;
int p2p_no_group_iface;
+ unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
+ if (force_freq)
+ *force_freq = 0;
+ if (pref_freq)
+ *pref_freq = 0;
+
+ size = P2P_MAX_PREF_CHANNELS;
+ if (force_freq && pref_freq &&
+ !wpas_p2p_setup_freqs(wpa_s, 0, (int *) force_freq,
+ (int *) pref_freq, 0, pref_freq_list, &size))
+ wpas_p2p_set_own_freq_preference(wpa_s,
+ *force_freq ? *force_freq :
+ *pref_freq);
+
/*
* For non-concurrent capable devices:
* If persistent_go, then no new.
@@ -628,36 +661,21 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
* If client, then no GO.
*/
go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ if (go_wpa_s)
+ owned_members = p2p_get_group_num_members(go_wpa_s->p2p_group);
persistent_go = wpas_p2p_get_persistent_go(wpa_s);
p2p_no_group_iface = !wpas_p2p_create_iface(wpa_s);
+ cli_wpa_s = wpas_p2p_get_cli_group(wpa_s);
- wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
- go_wpa_s, persistent_go);
-
- for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
- tmp_wpa_s = tmp_wpa_s->next) {
- for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
- wpa_printf(MSG_DEBUG,
- "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
- tmp_wpa_s, s, s->disabled,
- s->p2p_group, s->mode);
- if (!s->disabled && s->p2p_group) {
- if (s->mode == WPAS_MODE_P2P_GO) {
- owned_members +=
- p2p_get_group_num_members(
- tmp_wpa_s->p2p_group);
- owner++;
- } else
- client++;
- }
- }
- }
+ wpa_printf(MSG_DEBUG,
+ "P2P: GO(iface)=%p members=%u CLI(iface)=%p persistent(ssid)=%p",
+ go_wpa_s, owned_members, cli_wpa_s, persistent_go);
/* If not concurrent, restrict our choices */
if (p2p_no_group_iface) {
wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
- if (client)
+ if (cli_wpa_s)
return P2PS_SETUP_NONE;
if (go_wpa_s) {
@@ -689,10 +707,20 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
/* If a required role has been specified, handle it here */
if (role && role != P2PS_SETUP_NEW) {
switch (incoming) {
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ /*
+ * Peer has an active GO, so if the role allows it and
+ * we do not have any active roles, become client.
+ */
+ if ((role & P2PS_SETUP_CLIENT) && !go_wpa_s &&
+ !cli_wpa_s)
+ return P2PS_SETUP_CLIENT;
+
+ /* fall through */
+
case P2PS_SETUP_NONE:
case P2PS_SETUP_NEW:
- case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
- case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
conncap = role;
goto grp_owner;
@@ -701,7 +729,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
* Must be a complimentary role - cannot be a client to
* more than one peer.
*/
- if (incoming == role || client)
+ if (incoming == role || cli_wpa_s)
return P2PS_SETUP_NONE;
return P2PS_SETUP_CLIENT;
@@ -727,7 +755,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
switch (incoming) {
case P2PS_SETUP_NONE:
case P2PS_SETUP_NEW:
- if (client)
+ if (cli_wpa_s)
conncap = P2PS_SETUP_GROUP_OWNER;
else if (!owned_members)
conncap = P2PS_SETUP_NEW;
@@ -742,13 +770,13 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
break;
case P2PS_SETUP_GROUP_OWNER:
- if (!client)
+ if (!cli_wpa_s)
conncap = P2PS_SETUP_CLIENT;
break;
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
- if (client)
+ if (cli_wpa_s)
conncap = P2PS_SETUP_GROUP_OWNER;
else {
u8 r;
@@ -770,15 +798,14 @@ grp_owner:
(!incoming && (conncap & P2PS_SETUP_NEW))) {
if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
conncap &= ~P2PS_SETUP_GROUP_OWNER;
- wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
- owner, owned_members, conncap);
s = wpas_p2p_get_persistent_go(wpa_s);
-
- if (!s && !owner && p2p_no_group_iface) {
+ if (!s && !go_wpa_s && p2p_no_group_iface) {
p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->p2p_mgmt ?
+ wpa_s->parent->own_addr :
wpa_s->own_addr);
- } else if (!s && !owner) {
+ } else if (!s && !go_wpa_s) {
if (wpas_p2p_add_group_interface(wpa_s,
WPA_IF_P2P_GO) < 0) {
wpa_printf(MSG_ERROR,
@@ -850,7 +877,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
wpa_s->ifname, wpa_s->cross_connect_uplink);
}
@@ -881,7 +908,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
break;
}
if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_REMOVED "%s %s%s",
wpa_s->ifname, gtype, reason);
}
@@ -891,7 +918,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL) > 0) {
+ wpa_s->p2pdev, NULL) > 0) {
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
"timeout");
wpa_s->p2p_in_provisioning = 0;
@@ -926,6 +953,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
return 1;
}
+ /*
+ * The primary interface was used for P2P group operations, so
+ * need to reset its p2pdev.
+ */
+ wpa_s->p2pdev = wpa_s->parent;
+
if (!wpa_s->p2p_go_group_formation_completed) {
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
@@ -1043,7 +1076,7 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
"go_dev_addr=" MACSTR,
MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
- return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP);
}
@@ -1101,7 +1134,8 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s->auth_alg = WPA_AUTH_ALG_OPEN;
s->key_mgmt = WPA_KEY_MGMT_PSK;
s->proto = WPA_PROTO_RSN;
- s->pairwise_cipher = WPA_CIPHER_CCMP;
+ s->pbss = ssid->pbss;
+ s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
s->export_keys = 1;
if (ssid->passphrase) {
os_free(s->passphrase);
@@ -1241,7 +1275,7 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
* Include PSK/passphrase only in the control interface message and
* leave it out from the debug log entry.
*/
- wpa_msg_global_ctrl(wpa_s->parent, MSG_INFO,
+ wpa_msg_global_ctrl(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_STARTED
"%s %s ssid=\"%s\" freq=%d%s%s%s%s%s go_dev_addr="
MACSTR "%s%s",
@@ -1267,7 +1301,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
/*
* This callback is likely called for the main interface. Update wpa_s
@@ -1284,7 +1317,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
wpa_s->group_formation_reported = 1;
if (!success) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
if (already_deleted)
@@ -1294,7 +1327,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
return;
}
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_SUCCESS);
ssid = wpa_s->current_ssid;
@@ -1342,16 +1375,15 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
}
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
- ssid, go_dev_addr);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
else {
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
}
- if (network_id < 0 && ssid)
- network_id = ssid->id;
+
if (!client) {
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0);
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
}
}
@@ -1368,6 +1400,25 @@ struct send_action_work {
};
+static void wpas_p2p_free_send_action_work(struct wpa_supplicant *wpa_s)
+{
+ struct send_action_work *awork = wpa_s->p2p_send_action_work->ctx;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Free Action frame radio work @%p (freq=%u dst="
+ MACSTR " src=" MACSTR " bssid=" MACSTR " wait_time=%u)",
+ wpa_s->p2p_send_action_work, awork->freq,
+ MAC2STR(awork->dst), MAC2STR(awork->src),
+ MAC2STR(awork->bssid), awork->wait_time);
+ wpa_hexdump(MSG_DEBUG, "P2P: Freeing pending Action frame",
+ awork->buf, awork->len);
+ os_free(awork);
+ wpa_s->p2p_send_action_work->ctx = NULL;
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+}
+
+
static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -1377,9 +1428,7 @@ static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
return;
wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out");
- os_free(wpa_s->p2p_send_action_work->ctx);
- radio_work_done(wpa_s->p2p_send_action_work);
- wpa_s->p2p_send_action_work = NULL;
+ wpas_p2p_free_send_action_work(wpa_s);
}
@@ -1387,11 +1436,13 @@ static void wpas_p2p_action_tx_clear(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_send_action_work) {
struct send_action_work *awork;
+
awork = wpa_s->p2p_send_action_work->ctx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Clear Action TX work @%p (wait_time=%u)",
+ wpa_s->p2p_send_action_work, awork->wait_time);
if (awork->wait_time == 0) {
- os_free(awork);
- radio_work_done(wpa_s->p2p_send_action_work);
- wpa_s->p2p_send_action_work = NULL;
+ wpas_p2p_free_send_action_work(wpa_s);
} else {
/*
* In theory, this should not be needed, but number of
@@ -1447,7 +1498,7 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
wpa_s->pending_pd_before_join = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
"during p2p_connect-auto");
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=no-ACK-to-PD-Req");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
@@ -1590,11 +1641,11 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
} else if (res->wps_method == WPS_NFC) {
wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
res->peer_interface_addr,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_oob_dev_pw_id, 1,
- wpa_s->parent->p2p_oob_dev_pw_id ==
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_oob_dev_pw_id, 1,
+ wpa_s->p2pdev->p2p_oob_dev_pw_id ==
DEV_PW_NFC_CONNECTION_HANDOVER ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash :
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash :
NULL,
NULL, 0, 0);
#endif /* CONFIG_WPS_NFC */
@@ -1620,7 +1671,7 @@ static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
if (!wpa_s->ap_iface)
return;
- persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+ persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid,
ssid->ssid_len);
if (persistent == NULL)
return;
@@ -1685,8 +1736,8 @@ static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
static void p2p_config_write(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_CONFIG_WRITE
- if (wpa_s->parent->conf->update_config &&
- wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ if (wpa_s->p2pdev->conf->update_config &&
+ wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf))
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
}
@@ -1697,7 +1748,15 @@ static void p2p_go_configured(void *ctx, void *data)
struct wpa_supplicant *wpa_s = ctx;
struct p2p_go_neg_results *params = data;
struct wpa_ssid *ssid;
- int network_id = -1;
+
+ wpa_s->ap_configured_cb = NULL;
+ wpa_s->ap_configured_cb_ctx = NULL;
+ wpa_s->ap_configured_cb_data = NULL;
+ if (!wpa_s->go_params) {
+ wpa_printf(MSG_ERROR,
+ "P2P: p2p_go_configured() called with wpa_s->go_params == NULL");
+ return;
+ }
p2p_go_save_group_common_freqs(wpa_s, params);
p2p_go_dump_common_freqs(wpa_s);
@@ -1715,8 +1774,8 @@ static void p2p_go_configured(void *ctx, void *data)
params->persistent_group, "");
wpa_s->group_formation_reported = 1;
- if (wpa_s->parent->p2ps_method_config_any) {
- if (is_zero_ether_addr(wpa_s->parent->p2ps_join_addr)) {
+ if (wpa_s->p2pdev->p2ps_method_config_any) {
+ if (is_zero_ether_addr(wpa_s->p2pdev->p2ps_join_addr)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2PS: Setting default PIN for ANY");
wpa_supplicant_ap_wps_pin(wpa_s, NULL,
@@ -1725,24 +1784,24 @@ static void p2p_go_configured(void *ctx, void *data)
} else {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2PS: Setting default PIN for " MACSTR,
- MAC2STR(wpa_s->parent->p2ps_join_addr));
+ MAC2STR(wpa_s->p2pdev->p2ps_join_addr));
wpa_supplicant_ap_wps_pin(
- wpa_s, wpa_s->parent->p2ps_join_addr,
+ wpa_s, wpa_s->p2pdev->p2ps_join_addr,
"12345670", NULL, 0, 0);
}
- wpa_s->parent->p2ps_method_config_any = 0;
+ wpa_s->p2pdev->p2ps_method_config_any = 0;
}
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
- network_id = wpas_p2p_store_persistent_group(
- wpa_s->parent, ssid,
+ wpas_p2p_store_persistent_group(
+ wpa_s->p2pdev, ssid,
wpa_s->global->p2p_dev_addr);
wpas_p2p_add_psk_list(wpa_s, ssid);
}
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid,
+ params->persistent_group, 0);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
@@ -1753,11 +1812,11 @@ static void p2p_go_configured(void *ctx, void *data)
wpa_s->p2p_go_group_formation_completed = 0;
wpa_s->global->p2p_group_formation = wpa_s;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
eloop_register_timeout(
wpa_s->p2p_first_connection_timeout, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
return;
@@ -1775,17 +1834,17 @@ static void p2p_go_configured(void *ctx, void *data)
params->peer_device_addr);
#ifdef CONFIG_WPS_NFC
} else if (params->wps_method == WPS_NFC) {
- if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
DEV_PW_NFC_CONNECTION_HANDOVER &&
- !wpa_s->parent->p2p_oob_dev_pw) {
+ !wpa_s->p2pdev->p2p_oob_dev_pw) {
wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
return;
}
wpas_ap_wps_add_nfc_pw(
- wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_peer_oob_pk_hash_known ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+ wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
#endif /* CONFIG_WPS_NFC */
} else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
@@ -1822,12 +1881,14 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
- ssid->p2p_persistent_group = params->persistent_group;
+ ssid->p2p_persistent_group = !!params->persistent_group;
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
ssid->ht40 = params->ht40;
ssid->vht = params->vht;
+ ssid->max_oper_chwidth = params->max_oper_chwidth;
+ ssid->vht_center_freq2 = params->vht_center_freq2;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1845,6 +1906,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
*/
ssid->pairwise_cipher = WPA_CIPHER_GCMP;
ssid->group_cipher = WPA_CIPHER_GCMP;
+ /* P2P GO in 60 GHz is always a PCP (PBSS) */
+ ssid->pbss = 1;
}
if (os_strlen(params->passphrase) > 0) {
ssid->passphrase = os_strdup(params->passphrase);
@@ -1861,7 +1924,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
else if (ssid->passphrase)
wpa_config_update_psk(ssid);
- ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
+ ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
@@ -1885,7 +1948,12 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d = dst->conf;
s = src->conf;
-#define C(n) if (s->n) d->n = os_strdup(s->n)
+#define C(n) \
+do { \
+ if (s->n && !d->n) \
+ d->n = os_strdup(s->n); \
+} while (0)
+
C(device_name);
C(manufacturer);
C(model_name);
@@ -1913,7 +1981,10 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d->disable_scan_offload = s->disable_scan_offload;
d->passive_scan = s->passive_scan;
- if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
+ if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
+ !d->wps_nfc_pw_from_config) {
+ wpabuf_free(d->wps_nfc_dh_privkey);
+ wpabuf_free(d->wps_nfc_dh_pubkey);
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
}
@@ -2071,7 +2142,7 @@ static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
int already_deleted)
{
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
wpas_group_formation_completed(wpa_s, 0, already_deleted);
@@ -2082,9 +2153,9 @@ static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure");
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
wpa_s->global->p2p_fail_on_wps_complete = 0;
}
@@ -2095,15 +2166,16 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
return;
/* Speed up group formation timeout since this cannot succeed */
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *group_wpa_s;
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s);
@@ -2129,6 +2201,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
+ res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
+ res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
"freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
@@ -2154,7 +2228,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
}
if (wpa_s->create_p2p_iface) {
- struct wpa_supplicant *group_wpa_s =
+ group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go);
if (group_wpa_s == NULL) {
wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -2163,31 +2237,27 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_p2p_group_formation_failed(wpa_s, 1);
return;
}
- if (group_wpa_s != wpa_s) {
- os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
- sizeof(group_wpa_s->p2p_pin));
- group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
- }
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
- group_wpa_s->p2p_in_provisioning = 1;
-
- if (res->role_go) {
- wpas_start_wps_go(group_wpa_s, res, 1);
- } else {
- os_get_reltime(&group_wpa_s->scan_min_time);
- wpas_start_wps_enrollee(group_wpa_s, res);
- }
} else {
- wpa_s->p2p_in_provisioning = 1;
- wpa_s->global->p2p_group_formation = wpa_s;
+ group_wpa_s = wpa_s->parent;
+ wpa_s->global->p2p_group_formation = group_wpa_s;
+ if (group_wpa_s != wpa_s)
+ wpas_p2p_clone_config(group_wpa_s, wpa_s);
+ }
- if (res->role_go) {
- wpas_start_wps_go(wpa_s, res, 1);
- } else {
- os_get_reltime(&wpa_s->scan_min_time);
- wpas_start_wps_enrollee(ctx, res);
- }
+ group_wpa_s->p2p_in_provisioning = 1;
+ group_wpa_s->p2pdev = wpa_s;
+ if (group_wpa_s != wpa_s) {
+ os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
+ sizeof(group_wpa_s->p2p_pin));
+ group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+ }
+ if (res->role_go) {
+ wpas_start_wps_go(group_wpa_s, res, 1);
+ } else {
+ os_get_reltime(&group_wpa_s->scan_min_time);
+ wpas_start_wps_enrollee(group_wpa_s, res);
}
wpa_s->p2p_long_listen = 0;
@@ -2308,6 +2378,10 @@ static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
static void wpas_find_stopped(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->p2p_scan_work && wpas_abort_ongoing_scan(wpa_s) < 0)
+ wpa_printf(MSG_DEBUG, "P2P: Abort ongoing scan failed");
+
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
wpas_notify_p2p_find_stopped(wpa_s);
}
@@ -2521,7 +2595,13 @@ static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
params[sizeof(params) - 1] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY) {
- generated_pin = wps_generate_pin();
+ if (wps_generate_pin(&generated_pin) < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
+ wpas_notify_p2p_provision_discovery(
+ wpa_s, peer, 0 /* response */,
+ P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+ return;
+ }
wpas_prov_disc_local_display(wpa_s, peer, params,
generated_pin);
} else if (config_methods & WPS_CONFIG_KEYPAD)
@@ -2566,7 +2646,13 @@ static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
if (config_methods & WPS_CONFIG_DISPLAY)
wpas_prov_disc_local_keypad(wpa_s, peer, params);
else if (config_methods & WPS_CONFIG_KEYPAD) {
- generated_pin = wps_generate_pin();
+ if (wps_generate_pin(&generated_pin) < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
+ wpas_notify_p2p_provision_discovery(
+ wpa_s, peer, 0 /* response */,
+ P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+ return;
+ }
wpas_prov_disc_local_display(wpa_s, peer, params,
generated_pin);
} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
@@ -2589,7 +2675,7 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
if (wpa_s->p2p_fallback_to_go_neg) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
"failed - fall back to GO Negotiation");
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=PD-failed");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
@@ -2685,6 +2771,29 @@ static int wpas_p2p_go_is_peer_freq(struct wpa_supplicant *wpa_s, int freq)
}
+static int wpas_sta_check_ecsa(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ int *ecsa_support = ctx;
+
+ *ecsa_support &= sta->ecsa_supported;
+
+ return 0;
+}
+
+
+/* Check if all the peers support eCSA */
+static int wpas_p2p_go_clients_support_ecsa(struct wpa_supplicant *wpa_s)
+{
+ int ecsa_support = 1;
+
+ ap_for_each_sta(wpa_s->ap_iface->bss[0], wpas_sta_check_ecsa,
+ &ecsa_support);
+
+ return ecsa_support;
+}
+
+
/**
* Pick the best frequency to use from all the currently used frequencies.
*/
@@ -2811,7 +2920,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
"invitation");
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
}
- os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
+ if (wpa_s->p2p_mgmt)
+ os_memcpy(group_bssid, wpa_s->parent->own_addr,
+ ETH_ALEN);
+ else
+ os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
} else if (s->mode == WPAS_MODE_P2P_GO) {
*go = 1;
if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0)
@@ -2893,12 +3006,31 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
+ if (go) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR
+ " persistent=%d freq=%d",
+ MAC2STR(sa), s->id, op_freq);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR
+ " persistent=%d",
+ MAC2STR(sa), s->id);
+ }
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " bssid=" MACSTR " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr),
+ MAC2STR(bssid));
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0, op_freq,
ssid, ssid_len);
@@ -2999,7 +3131,7 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
!ssid->p2p_persistent_group)
return; /* Not operating as a GO in persistent group */
- ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
+ ssid = wpas_p2p_get_persistent(wpa_s->p2pdev, peer,
ssid->ssid, ssid->ssid_len);
wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
}
@@ -3027,9 +3159,37 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
status, MAC2STR(peer));
if (wpa_s->pending_invite_ssid_id == -1) {
+ struct wpa_supplicant *group_if =
+ wpa_s->global->p2p_invite_group;
+
if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
wpas_remove_persistent_client(wpa_s, peer);
- return; /* Invitation to active group */
+
+ /*
+ * Invitation to an active group. If this is successful and we
+ * are the GO, set the client wait to postpone some concurrent
+ * operations and to allow provisioning and connection to happen
+ * more quickly.
+ */
+ if (status == P2P_SC_SUCCESS &&
+ group_if && group_if->current_ssid &&
+ group_if->current_ssid->mode == WPAS_MODE_P2P_GO) {
+ os_get_reltime(&wpa_s->global->p2p_go_wait_client);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (group_if->p2p_go_csa_on_inv) {
+ wpa_printf(MSG_DEBUG,
+ "Testing: force P2P GO CSA after invitation");
+ eloop_cancel_timeout(
+ wpas_p2p_reconsider_moving_go,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 0, 50000,
+ wpas_p2p_reconsider_moving_go,
+ wpa_s, NULL);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ }
+ return;
}
if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
@@ -3083,7 +3243,9 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
freq,
+ wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3169,21 +3331,6 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
}
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes,
- enum hostapd_hw_mode mode)
-{
- u16 i;
-
- for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
- return &modes[i];
- }
-
- return NULL;
-}
-
-
enum chan_allowed {
NOT_ALLOWED, NO_IR, ALLOWED
};
@@ -3217,49 +3364,12 @@ static int has_channel(struct wpa_global *global,
}
-struct p2p_oper_class_map {
- enum hostapd_hw_mode mode;
- u8 op_class;
- u8 min_chan;
- u8 max_chan;
- u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw;
-};
-
-static const struct p2p_oper_class_map op_class[] = {
- { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
-#if 0 /* Do not enable HT40 on 2 GHz for now */
- { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
-#endif
- { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
-
- /*
- * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
- * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
- * 80 MHz, but currently use the following definition for simplicity
- * (these center frequencies are not actual channels, which makes
- * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
- * removing invalid channels.
- */
- { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
- { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160 },
- { -1, 0, 0, 0, 0, BW20 }
-};
-
-
static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel)
{
u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
- unsigned int i;
+ size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
@@ -3315,6 +3425,75 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
}
+static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ u8 center_channels[] = { 50, 114 };
+ unsigned int i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+ /*
+ * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+ * so the center channel is 14 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 14 &&
+ channel <= center_channels[i] + 14)
+ return center_channels[i];
+
+ return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ u8 center_chan;
+ int i, flags;
+ enum chan_allowed res, ret = ALLOWED;
+
+ center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+ /* VHT 160 MHz uses DFS channels in most countries. */
+
+ /* Check all the channels are available */
+ for (i = 0; i < 8; i++) {
+ int adj_chan = center_chan - 14 + i * 4;
+
+ res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+ if (res == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if (res == NO_IR)
+ ret = NO_IR;
+
+ if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90))
+ return NOT_ALLOWED;
+ if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70))
+ return NOT_ALLOWED;
+ if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50))
+ return NOT_ALLOWED;
+ if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30))
+ return NOT_ALLOWED;
+ if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))
+ return NOT_ALLOWED;
+ }
+
+ return ret;
+}
+
+
static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel, u8 bw)
@@ -3333,6 +3512,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
} else if (bw == BW80) {
res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+ } else if (bw == BW160) {
+ res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3359,11 +3540,14 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
cla = cli_cla = 0;
- for (op = 0; op_class[op].op_class; op++) {
- const struct p2p_oper_class_map *o = &op_class[op];
+ for (op = 0; global_op_class[op].op_class; op++) {
+ const struct oper_class_map *o = &global_op_class[op];
u8 ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
+ if (o->p2p == NO_P2P_SUPP)
+ continue;
+
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
@@ -3418,10 +3602,13 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
int op;
enum chan_allowed ret;
- for (op = 0; op_class[op].op_class; op++) {
- const struct p2p_oper_class_map *o = &op_class[op];
+ for (op = 0; global_op_class[op].op_class; op++) {
+ const struct oper_class_map *o = &global_op_class[op];
u8 ch;
+ if (o->p2p == NO_P2P_SUPP)
+ continue;
+
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
if (o->mode != HOSTAPD_MODE_IEEE80211A ||
(o->bw != BW40PLUS && o->bw != BW40MINUS) ||
@@ -3446,6 +3633,15 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
}
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160))
+ return 0;
+ return wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -3577,6 +3773,7 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
return -1;
}
+ p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
wpa_s->pending_interface_name[0] = '\0';
return 0;
}
@@ -3638,11 +3835,12 @@ static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
static int wpas_get_go_info(void *ctx, u8 *intended_addr,
- u8 *ssid, size_t *ssid_len, int *group_iface)
+ u8 *ssid, size_t *ssid_len, int *group_iface,
+ unsigned int *freq)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *go;
struct wpa_ssid *s;
- u8 bssid[ETH_ALEN];
/*
* group_iface will be set to 1 only if a dedicated interface for P2P
@@ -3652,17 +3850,25 @@ static int wpas_get_go_info(void *ctx, u8 *intended_addr,
* that the pending interface should be used.
*/
*group_iface = 0;
- s = wpas_p2p_group_go_ssid(wpa_s, bssid);
- if (!s) {
+
+ if (freq)
+ *freq = 0;
+
+ go = wpas_p2p_get_go_group(wpa_s);
+ if (!go) {
s = wpas_p2p_get_persistent_go(wpa_s);
*group_iface = wpas_p2p_create_iface(wpa_s);
if (s)
- os_memcpy(bssid, s->bssid, ETH_ALEN);
+ os_memcpy(intended_addr, s->bssid, ETH_ALEN);
else
return 0;
+ } else {
+ s = go->current_ssid;
+ os_memcpy(intended_addr, go->own_addr, ETH_ALEN);
+ if (freq)
+ *freq = go->assoc_freq;
}
- os_memcpy(intended_addr, bssid, ETH_ALEN);
os_memcpy(ssid, s->ssid, s->ssid_len);
*ssid_len = s->ssid_len;
@@ -3750,11 +3956,13 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
const u8 *persist_ssid,
size_t persist_ssid_size, int response_done,
int prov_start, const char *session_info,
- const u8 *feat_cap, size_t feat_cap_len)
+ const u8 *feat_cap, size_t feat_cap_len,
+ unsigned int freq,
+ const u8 *group_ssid, size_t group_ssid_len)
{
struct wpa_supplicant *wpa_s = ctx;
u8 mac[ETH_ALEN];
- struct wpa_ssid *persistent_go, *stale, *s;
+ struct wpa_ssid *persistent_go, *stale, *s = NULL;
int save_config = 0;
struct wpa_supplicant *go_wpa_s;
char feat_cap_str[256];
@@ -3825,8 +4033,9 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
}
/* Clean up stale persistent groups with this device */
- s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
- persist_ssid_size);
+ if (persist_ssid && persist_ssid_size)
+ s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
+ persist_ssid_size);
if (persist_ssid && s && s->mode != WPAS_MODE_P2P_GO &&
is_zero_ether_addr(grp_mac)) {
@@ -3908,6 +4117,7 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
go_ifname[0] = '\0';
if (!go_wpa_s) {
wpa_s->global->pending_p2ps_group = 1;
+ wpa_s->global->pending_p2ps_group_freq = freq;
if (!wpas_p2p_create_iface(wpa_s))
os_memcpy(go_ifname, wpa_s->ifname,
@@ -3922,7 +4132,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
dev, adv_mac, ses_mac,
grp_mac, adv_id, ses_id, 0, 0,
- NULL, 0, 0, 0, NULL, NULL, 0);
+ NULL, 0, 0, 0, NULL, NULL, 0, 0,
+ NULL, 0);
return;
}
@@ -3930,13 +4141,13 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 0);
} else if (response_done) {
- wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -3989,16 +4200,24 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
}
if (conncap == P2PS_SETUP_CLIENT) {
+ char ssid_hex[32 * 2 + 1];
+
+ if (group_ssid)
+ wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex),
+ group_ssid, group_ssid_len);
+ else
+ ssid_hex[0] = '\0';
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_P2PS_PROVISION_DONE MACSTR
" status=%d conncap=%x"
" adv_id=%x adv_mac=" MACSTR
" session=%x mac=" MACSTR
- " dev_passwd_id=%d join=" MACSTR "%s",
+ " dev_passwd_id=%d join=" MACSTR "%s%s%s",
MAC2STR(dev), status, conncap,
adv_id, MAC2STR(adv_mac),
ses_id, MAC2STR(ses_mac),
- passwd_id, MAC2STR(grp_mac), feat_cap_str);
+ passwd_id, MAC2STR(grp_mac), feat_cap_str,
+ group_ssid ? " group_ssid=" : "", ssid_hex);
} else {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_P2PS_PROVISION_DONE MACSTR
@@ -4025,10 +4244,13 @@ static int wpas_prov_disc_resp_cb(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *persistent_go;
+ unsigned int freq;
if (!wpa_s->global->pending_p2ps_group)
return 0;
+ freq = wpa_s->global->pending_p2ps_group_freq;
+ wpa_s->global->pending_p2ps_group_freq = 0;
wpa_s->global->pending_p2ps_group = 0;
if (wpas_p2p_get_go_group(wpa_s))
@@ -4037,11 +4259,11 @@ static int wpas_prov_disc_resp_cb(void *ctx)
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
} else {
- wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
}
return 1;
@@ -4333,8 +4555,7 @@ static void wpas_p2p_deinit_global(struct wpa_global *global)
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
{
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
- wpa_s->conf->p2p_no_group_iface)
+ if (wpa_s->conf->p2p_no_group_iface)
return 0; /* separate interface disabled per configuration */
if (wpa_s->drv_flags &
(WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@@ -4415,7 +4636,7 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
MAC2STR(wpa_s->pending_join_dev_addr));
return;
}
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
}
@@ -4551,7 +4772,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
if (join < 0) {
wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
"running a GO -> use GO Negotiation");
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=peer-not-running-GO");
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
@@ -4559,10 +4780,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_persistent_group, 0, 0, 0,
wpa_s->p2p_go_intent,
wpa_s->p2p_connect_freq,
+ wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
- wpa_s->p2p_go_vht);
+ wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
+ NULL, 0);
return;
}
@@ -4570,7 +4794,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
"try to join the group", join ? "" :
" in older scan");
if (!join) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED);
wpa_s->p2p_fallback_to_go_neg = 1;
}
@@ -4608,8 +4832,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
wpa_s->p2p_join_ssid,
wpa_s->p2p_join_ssid_len);
- }
- if (!bss) {
+ } else if (!bss) {
wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
MACSTR, MAC2STR(wpa_s->pending_join_iface_addr));
bss = wpa_bss_get_bssid_latest(wpa_s,
@@ -4640,7 +4863,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
u16 method;
if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE
"reason=FREQ_CONFLICT");
wpas_notify_p2p_group_formation_failure(
@@ -4708,7 +4931,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
start:
/* Start join operation immediately */
- wpas_p2p_join_start(wpa_s, 0, NULL, 0);
+ wpas_p2p_join_start(wpa_s, 0, wpa_s->p2p_join_ssid,
+ wpa_s->p2p_join_ssid_len);
}
@@ -4720,6 +4944,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
struct wpabuf *wps_ie, *ies;
size_t ielen;
int freqs[2] = { 0, 0 };
+ unsigned int bands;
os_memset(&params, 0, sizeof(params));
@@ -4745,22 +4970,6 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
return;
}
- ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
- if (ies == NULL) {
- wpabuf_free(wps_ie);
- wpas_p2p_scan_res_join(wpa_s, NULL);
- return;
- }
- wpabuf_put_buf(ies, wps_ie);
- wpabuf_free(wps_ie);
-
- p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
-
- params.p2p_probe = 1;
- params.extra_ies = wpabuf_head(ies);
- params.extra_ies_len = wpabuf_len(ies);
-
if (!freq) {
int oper_freq;
/*
@@ -4777,6 +4986,23 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
params.freqs = freqs;
}
+ ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+ if (ies == NULL) {
+ wpabuf_free(wps_ie);
+ wpas_p2p_scan_res_join(wpa_s, NULL);
+ return;
+ }
+ wpabuf_put_buf(ies, wps_ie);
+ wpabuf_free(wps_ie);
+
+ bands = wpas_get_bands(wpa_s, freqs);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
+
+ params.p2p_probe = 1;
+ params.extra_ies = wpabuf_head(ies);
+ params.extra_ies_len = wpabuf_len(ies);
+
/*
* Run a scan to update BSS table and start Provision Discovery once
* the new scan results become available.
@@ -4874,8 +5100,13 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
res.ssid_len = ssid_len;
os_memcpy(res.ssid, ssid, ssid_len);
} else {
- bss = wpa_bss_get_bssid_latest(wpa_s,
- wpa_s->pending_join_iface_addr);
+ if (ssid && ssid_len) {
+ bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
+ ssid, ssid_len);
+ } else {
+ bss = wpa_bss_get_bssid_latest(
+ wpa_s, wpa_s->pending_join_iface_addr);
+ }
if (bss) {
res.freq = bss->freq;
res.ssid_len = bss->ssid_len;
@@ -4883,6 +5114,11 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
bss->freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ } else if (ssid && ssid_len) {
+ res.ssid_len = ssid_len;
+ os_memcpy(res.ssid, ssid, ssid_len);
+ wpa_printf(MSG_DEBUG, "P2P: Join target GO (SSID %s)",
+ wpa_ssid_txt(ssid, ssid_len));
}
}
@@ -5067,12 +5303,17 @@ exit_free:
* initiating Group Owner negotiation
* @go_intent: GO Intent or -1 to use default
* @freq: Frequency for the group or 0 for auto-selection
+ * @freq2: Center frequency of segment 1 for the GO operating in VHT 80P80 mode
* @persistent_id: Persistent group credentials to use for forcing GO
* parameters or -1 to generate new values (SSID/passphrase)
* @pd: Whether to send Provision Discovery prior to GO Negotiation as an
* interoperability workaround when initiating group formation
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
+ * @vht_chwidth: Channel width supported by GO operating with VHT support
+ * (VHT_CHANWIDTH_*).
+ * @group_ssid: Specific Group SSID for join or %NULL if not set
+ * @group_ssid_len: Length of @group_ssid in octets
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -5080,8 +5321,10 @@ exit_free:
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join, int auth,
- int go_intent, int freq, int persistent_id, int pd,
- int ht40, int vht)
+ int go_intent, int freq, unsigned int vht_center_freq2,
+ int persistent_id, int pd, int ht40, int vht,
+ unsigned int vht_chwidth, const u8 *group_ssid,
+ size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -5105,6 +5348,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->global->p2p_fail_on_wps_complete = 0;
wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
wpa_s->p2ps_method_config_any = 0;
if (go_intent < 0)
@@ -5122,17 +5366,23 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_pd_before_go_neg = !!pd;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+ wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
else if (wps_method == WPS_PIN_DISPLAY) {
- ret = wps_generate_pin();
+ if (wps_generate_pin((unsigned int *) &ret) < 0)
+ return -1;
res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin),
"%08d", ret);
if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res))
wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
+ } else if (wps_method == WPS_P2PS) {
+ /* Force the P2Ps default PIN to be used */
+ os_strlcpy(wpa_s->p2p_pin, "12345670", sizeof(wpa_s->p2p_pin));
} else
wpa_s->p2p_pin[0] = '\0';
@@ -5161,7 +5411,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
}
wpa_s->user_initiated_pd = 1;
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
- auto_join, freq, NULL, 0) < 0)
+ auto_join, freq,
+ group_ssid, group_ssid_len) < 0)
return -1;
return ret;
}
@@ -5191,7 +5442,10 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
if_addr = wpa_s->pending_interface_addr;
} else {
- if_addr = wpa_s->own_addr;
+ if (wpa_s->p2p_mgmt)
+ if_addr = wpa_s->parent->own_addr;
+ else
+ if_addr = wpa_s->own_addr;
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
}
@@ -5520,29 +5774,51 @@ out:
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq, int ht40, int vht,
+ int freq, int vht_center_freq2, int ht40,
+ int vht, int max_oper_chwidth,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
unsigned int cand;
unsigned int num, i;
+ int ignore_no_freqs = 0;
+ int unused_channels = wpas_p2p_num_unused_channels(wpa_s) > 0;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
params->ht40 = ht40;
params->vht = vht;
-
- if (wpa_s->p2p_group_common_freqs_num)
- wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO",
- __func__);
+ params->max_oper_chwidth = max_oper_chwidth;
+ params->vht_center_freq2 = vht_center_freq2;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
if (!freqs)
return -1;
- num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ num = get_shared_radio_freqs_data(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO &&
+ wpa_s->wpa_state == WPA_COMPLETED) {
+ wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO",
+ __func__);
+
+ /*
+ * If the frequency selection is done for an active P2P GO that
+ * is not sharing a frequency, allow to select a new frequency
+ * even if there are no unused frequencies as we are about to
+ * move the P2P GO so its frequency can be re-used.
+ */
+ for (i = 0; i < num; i++) {
+ if (freqs[i].freq == wpa_s->current_ssid->frequency &&
+ freqs[i].flags == 0) {
+ ignore_no_freqs = 1;
+ break;
+ }
+ }
+ }
/* try using the forced freq */
if (freq) {
@@ -5563,7 +5839,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
}
- if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (!ignore_no_freqs && !unused_channels) {
wpa_printf(MSG_DEBUG,
"P2P: Cannot force GO on freq (%d MHz) as all the channels are in use",
freq);
@@ -5578,12 +5854,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
/* consider using one of the shared frequencies */
- if (num) {
+ if (num &&
+ (!wpa_s->conf->p2p_ignore_shared_freq || !unused_channels)) {
cand = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
wpa_printf(MSG_DEBUG,
"P2P: Use shared freq (%d MHz) for GO",
- freq);
+ cand);
params->freq = cand;
goto success;
}
@@ -5594,14 +5871,14 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
freqs[i].freq)) {
wpa_printf(MSG_DEBUG,
"P2P: Use shared freq (%d MHz) for GO",
- freq);
+ freqs[i].freq);
params->freq = freqs[i].freq;
goto success;
}
}
}
- if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (!ignore_no_freqs && !unused_channels) {
wpa_printf(MSG_DEBUG,
"P2P: Cannot force GO on any of the channels we are already using");
goto fail;
@@ -5714,9 +5991,20 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
struct wpa_supplicant *group_wpa_s;
if (!wpas_p2p_create_iface(wpa_s)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
- "operations");
+ if (wpa_s->p2p_mgmt) {
+ /*
+ * We may be called on the p2p_dev interface which
+ * cannot be used for group operations, so always use
+ * the primary interface.
+ */
+ wpa_s->parent->p2pdev = wpa_s;
+ wpa_s = wpa_s->parent;
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Use primary interface for group operations");
wpa_s->p2p_first_connection_timeout = 0;
+ if (wpa_s != wpa_s->p2pdev)
+ wpas_p2p_clone_config(wpa_s, wpa_s->p2pdev);
return wpa_s;
}
@@ -5746,15 +6034,18 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
* @persistent_group: Whether to create a persistent group
* @freq: Frequency for the group or 0 to indicate no hardcoding
+ * @vht_center_freq2: segment_1 center frequency for GO operating in VHT 80P80
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
+ * @vht_chwidth: channel bandwidth for GO operating with VHT support
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
* i.e., without using Group Owner Negotiation.
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq, int ht40, int vht)
+ int freq, int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth)
{
struct p2p_go_neg_results params;
@@ -5772,7 +6063,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
if (freq < 0)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
+ ht40, vht, max_oper_chwidth, NULL))
return -1;
if (params.freq &&
!p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
@@ -5826,8 +6118,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->proto = WPA_PROTO_RSN;
- ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->group_cipher = WPA_CIPHER_CCMP;
+ ssid->pbss = params->pbss;
+ ssid->pairwise_cipher = params->pbss ? WPA_CIPHER_GCMP :
+ WPA_CIPHER_CCMP;
+ ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->ssid = os_malloc(params->ssid_len);
if (ssid->ssid == NULL) {
@@ -5848,12 +6142,14 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
wpa_s->show_group_started = 1;
wpa_s->p2p_in_invitation = 1;
wpa_s->p2p_invite_go_freq = freq;
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->global->p2p_group_formation = wpa_s;
- eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
NULL);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
wpa_supplicant_select_network(wpa_s, ssid);
return 0;
@@ -5862,8 +6158,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int force_freq, int neg_freq, int ht40,
- int vht, const struct p2p_channels *channels,
+ int force_freq, int neg_freq,
+ int vht_center_freq2, int ht40,
+ int vht, int max_oper_chwidth,
+ const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
struct p2p_go_neg_results params;
@@ -5878,7 +6176,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
"already running");
if (go == 0 &&
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL)) {
+ wpa_s->p2pdev, NULL)) {
/*
* This can happen if Invitation Response frame was lost
* and the peer (GO of a persistent group) tries to
@@ -5891,7 +6189,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
"P2P: Reschedule group formation timeout since peer is still trying to invite us");
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
return 0;
}
@@ -5937,7 +6235,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
+ ht40, vht, max_oper_chwidth, channels))
return -1;
params.role_go = 1;
@@ -6019,7 +6318,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+ !ssid->p2p_group)
return NULL;
cfg = os_zalloc(sizeof(*cfg));
@@ -6042,6 +6342,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
+ cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
+ != 0;
group = p2p_group_init(wpa_s->global->p2p, cfg);
if (group == NULL)
@@ -6073,7 +6375,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
}
- eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
NULL);
wpa_s->p2p_go_group_formation_completed = 1;
if (ssid && ssid->mode == WPAS_MODE_INFRA) {
@@ -6088,7 +6390,9 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
P2P_MAX_INITIAL_CONN_WAIT);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
+ /* Complete group formation on successful data connection. */
+ wpa_s->p2p_go_group_formation_completed = 0;
} else if (ssid) {
/*
* Use a separate timeout for initial data connection to
@@ -6100,7 +6404,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
P2P_MAX_INITIAL_CONN_WAIT_GO);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
/*
* Complete group formation on first successful data connection
*/
@@ -6139,7 +6443,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
wpa_s->global->p2p_fail_on_wps_complete = 1;
eloop_deplete_timeout(0, 50000,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
}
@@ -6164,11 +6468,14 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
u16 config_methods;
wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->pending_pd_use = NORMAL_PD;
if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
p2ps_prov->conncap = p2ps_group_capability(
- wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+ wpa_s, P2PS_SETUP_NONE, p2ps_prov->role,
+ &p2ps_prov->force_freq, &p2ps_prov->pref_freq);
+
wpa_printf(MSG_DEBUG,
"P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
__func__, p2ps_prov->conncap,
@@ -6229,7 +6536,12 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
if (!offchannel_pending_action_tx(wpa_s))
return;
- wpas_p2p_action_tx_clear(wpa_s);
+ if (wpa_s->p2p_send_action_work) {
+ wpas_p2p_free_send_action_work(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ }
wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
"operation request");
@@ -6320,6 +6632,12 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->p2p_lo_started) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Cannot start P2P listen, it is offloaded");
+ return -1;
+ }
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
@@ -6393,7 +6711,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
return 0;
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len, rx_freq)) {
+ ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
case P2P_PREQ_NOT_P2P:
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
ssi_signal);
@@ -6425,12 +6743,15 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
{
+ unsigned int bands;
+
if (wpa_s->global->p2p_disabled)
return;
if (wpa_s->global->p2p == NULL)
return;
- p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
+ bands = wpas_get_bands(wpa_s, NULL);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
}
@@ -6460,7 +6781,8 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
/* Invite to reinvoke a persistent group */
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40, int vht, int pref_freq)
+ int vht_center_freq2, int ht40, int vht, int max_chwidth,
+ int pref_freq)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -6477,6 +6799,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
+ wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
+ wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -6493,7 +6818,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
bssid = wpa_s->pending_interface_addr;
- } else
+ } else if (wpa_s->p2p_mgmt)
+ bssid = wpa_s->parent->own_addr;
+ else
bssid = wpa_s->own_addr;
} else {
role = P2P_INVITE_ROLE_CLIENT;
@@ -6507,11 +6834,12 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
pref_freq_list, &size);
if (res)
return res;
- p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size);
+
if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
no_pref_freq_given && pref_freq > 0 &&
wpa_s->num_multichan_concurrent > 1 &&
@@ -6549,6 +6877,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->p2p_persistent_go_freq = 0;
wpa_s->p2p_go_ht40 = 0;
wpa_s->p2p_go_vht = 0;
+ wpa_s->p2p_go_vht_center_freq2 = 0;
+ wpa_s->p2p_go_max_oper_chwidth = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -6568,7 +6898,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
- wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
+ wpas_p2p_get_persistent(wpa_s->p2pdev, peer_addr,
ssid->ssid, ssid->ssid_len);
if (ssid->mode == WPAS_MODE_P2P_GO) {
@@ -6591,7 +6921,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
(int) wpa_s->assoc_freq;
}
- wpa_s->parent->pending_invite_ssid_id = -1;
+ wpa_s->p2pdev->pending_invite_ssid_id = -1;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -6614,7 +6944,6 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
int persistent;
int freq;
u8 ip[3 * 4];
@@ -6622,13 +6951,22 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
if (!wpa_s->show_group_started || !ssid)
return;
wpa_s->show_group_started = 0;
+ if (!wpa_s->p2p_go_group_formation_completed &&
+ wpa_s->global->p2p_group_formation == wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Marking group formation completed on client on data connection");
+ wpa_s->p2p_go_group_formation_completed = 1;
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ wpa_s->p2p_in_invitation = 0;
+ }
os_memset(go_dev_addr, 0, ETH_ALEN);
if (ssid->bssid_set)
@@ -6664,11 +7002,10 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
ip_addr);
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
- ssid, go_dev_addr);
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1);
}
@@ -7001,7 +7338,7 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
iface->cross_connect_enabled = 0;
iface->cross_connect_in_use = 0;
- wpa_msg_global(iface->parent, MSG_INFO,
+ wpa_msg_global(iface->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
iface->ifname,
iface->cross_connect_uplink);
@@ -7031,7 +7368,7 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
continue;
iface->cross_connect_in_use = 1;
- wpa_msg_global(iface->parent, MSG_INFO,
+ wpa_msg_global(iface->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
iface->ifname, iface->cross_connect_uplink);
}
@@ -7051,7 +7388,7 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
if (!iface->cross_connect_in_use)
continue;
- wpa_msg_global(iface->parent, MSG_INFO,
+ wpa_msg_global(iface->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
iface->ifname, iface->cross_connect_uplink);
iface->cross_connect_in_use = 0;
@@ -7114,7 +7451,7 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
break;
wpa_s->cross_connect_in_use = 1;
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
wpa_s->ifname, wpa_s->cross_connect_uplink);
break;
@@ -7130,8 +7467,8 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
"session overlap");
- if (wpa_s != wpa_s->parent)
- wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
+ if (wpa_s != wpa_s->p2pdev)
+ wpa_msg_ctrl(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_OVERLAP);
wpas_p2p_group_formation_failed(wpa_s, 0);
return 1;
}
@@ -7238,7 +7575,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
wpa_s->ifname);
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
if (wpa_s->p2p_in_provisioning) {
wpas_group_formation_completed(wpa_s, 0, 0);
break;
@@ -7251,6 +7588,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
wpa_s->ifname);
found = 1;
wpas_p2p_group_formation_failed(wpa_s, 0);
+ break;
}
}
@@ -7367,7 +7705,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
{
if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL) > 0) {
+ wpa_s->p2pdev, NULL) > 0) {
/**
* Remove the network by scheduling the group formation
* timeout to happen immediately. The teardown code
@@ -7379,7 +7717,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
"P2P group network getting removed");
eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
}
@@ -7423,7 +7761,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL) > 0) {
+ wpa_s->p2pdev, NULL) > 0) {
/*
* This can happen if WPS provisioning step is not terminated
* cleanly (e.g., P2P Client does not send WSC_Done). Since the
@@ -7479,10 +7817,12 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
- wpa_s->p2p_go_vht);
+ wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth, NULL, 0);
return ret;
}
@@ -7500,7 +7840,7 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
"fallback to GO Negotiation");
- wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=GO-not-found");
res = wpas_p2p_fallback_to_go_neg(wpa_s, 1);
@@ -7609,7 +7949,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
return;
}
- persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+ persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid,
ssid->ssid_len);
if (!persistent) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not find persistent group information to store the new PSK");
@@ -7638,7 +7978,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
os_free(last);
}
- wpas_p2p_remove_psk_entry(wpa_s->parent, persistent,
+ wpas_p2p_remove_psk_entry(wpa_s->p2pdev, persistent,
p2p_dev_addr ? p2p_dev_addr : mac_addr,
p2p_dev_addr == NULL);
if (p2p_dev_addr) {
@@ -7650,8 +7990,8 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
}
dl_list_add(&persistent->psk_list, &p->list);
- if (wpa_s->parent->conf->update_config &&
- wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ if (wpa_s->p2pdev->conf->update_config &&
+ wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf))
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
}
@@ -7830,14 +8170,14 @@ int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Two 4-way handshake failures for a P2P group - go_dev_addr="
MACSTR, MAC2STR(go_dev_addr));
- persistent = wpas_p2p_get_persistent(wpa_s->parent, go_dev_addr,
+ persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, go_dev_addr,
ssid->ssid,
ssid->ssid_len);
if (persistent == NULL || persistent->mode != WPAS_MODE_INFRA) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No matching persistent group stored");
goto disconnect;
}
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_PERSISTENT_PSK_FAIL "%d",
persistent->id);
disconnect:
@@ -8016,7 +8356,10 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
- params->go_freq, -1, 0, 1, 1);
+ params->go_freq, wpa_s->p2p_go_vht_center_freq2,
+ -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ params->go_ssid_len ? params->go_ssid : NULL,
+ params->go_ssid_len);
}
@@ -8043,17 +8386,17 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
return -1;
}
- if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
DEV_PW_NFC_CONNECTION_HANDOVER &&
- !wpa_s->parent->p2p_oob_dev_pw) {
+ !wpa_s->p2pdev->p2p_oob_dev_pw) {
wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
return -1;
}
res = wpas_ap_wps_add_nfc_pw(
- wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_peer_oob_pk_hash_known ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+ wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
if (res)
return res;
@@ -8071,16 +8414,16 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
- wpas_p2p_get_persistent(wpa_s->parent,
+ wpas_p2p_get_persistent(wpa_s->p2pdev,
params->peer->p2p_device_addr,
ssid->ssid, ssid->ssid_len);
- wpa_s->parent->pending_invite_ssid_id = -1;
+ wpa_s->p2pdev->pending_invite_ssid_id = -1;
return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr,
P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
ssid->ssid, ssid->ssid_len, ssid->frequency,
wpa_s->global->p2p_dev_addr, persistent, 0,
- wpa_s->parent->p2p_oob_dev_pw_id);
+ wpa_s->p2pdev->p2p_oob_dev_pw_id);
}
@@ -8092,7 +8435,9 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
"connection handover");
return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
- forced_freq, -1, 0, 1, 1);
+ forced_freq, wpa_s->p2p_go_vht_center_freq2,
+ -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ NULL, 0);
}
@@ -8106,7 +8451,9 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
"connection handover");
res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
- forced_freq, -1, 0, 1, 1);
+ forced_freq, wpa_s->p2p_go_vht_center_freq2,
+ -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ NULL, 0);
if (res)
return res;
@@ -8397,7 +8744,9 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
}
if_addr = wpa_s->pending_interface_addr;
- } else
+ } else if (wpa_s->p2p_mgmt)
+ if_addr = wpa_s->parent->own_addr;
+ else
if_addr = wpa_s->own_addr;
wpa_s->p2p_nfc_tag_enabled = enabled;
@@ -8473,14 +8822,115 @@ static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
{
+ struct hostapd_config *conf;
+ struct p2p_go_neg_results params;
+ struct csa_settings csa_settings;
+ struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+ int old_freq = current_ssid->frequency;
+ int ret;
+
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
wpa_dbg(wpa_s, MSG_DEBUG, "CSA is not enabled");
return -1;
}
- /* TODO: Add CSA support */
- wpa_dbg(wpa_s, MSG_DEBUG, "Moving GO with CSA is not implemented");
- return -1;
+ /*
+ * TODO: This function may not always work correctly. For example,
+ * when we have a running GO and a BSS on a DFS channel.
+ */
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, NULL)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Failed to select new frequency for GO");
+ return -1;
+ }
+
+ if (current_ssid->frequency == params.freq) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Selected same frequency - not moving GO");
+ return 0;
+ }
+
+ conf = hostapd_config_defaults();
+ if (!conf) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Failed to allocate default config");
+ return -1;
+ }
+
+ current_ssid->frequency = params.freq;
+ if (wpa_supplicant_conf_ap_ht(wpa_s, current_ssid, conf)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Failed to create new GO config");
+ ret = -1;
+ goto out;
+ }
+
+ if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: CSA to a different band is not supported");
+ ret = -1;
+ goto out;
+ }
+
+ os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.cs_count = P2P_GO_CSA_COUNT;
+ csa_settings.block_tx = P2P_GO_CSA_BLOCK_TX;
+ csa_settings.freq_params.freq = params.freq;
+ csa_settings.freq_params.sec_channel_offset = conf->secondary_channel;
+ csa_settings.freq_params.ht_enabled = conf->ieee80211n;
+ csa_settings.freq_params.bandwidth = conf->secondary_channel ? 40 : 20;
+
+ if (conf->ieee80211ac) {
+ int freq1 = 0, freq2 = 0;
+ u8 chan, opclass;
+
+ if (ieee80211_freq_to_channel_ext(params.freq,
+ conf->secondary_channel,
+ conf->vht_oper_chwidth,
+ &opclass, &chan) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "P2P CSA: Bad freq");
+ ret = -1;
+ goto out;
+ }
+
+ if (conf->vht_oper_centr_freq_seg0_idx)
+ freq1 = ieee80211_chan_to_freq(
+ NULL, opclass,
+ conf->vht_oper_centr_freq_seg0_idx);
+
+ if (conf->vht_oper_centr_freq_seg1_idx)
+ freq2 = ieee80211_chan_to_freq(
+ NULL, opclass,
+ conf->vht_oper_centr_freq_seg1_idx);
+
+ if (freq1 < 0 || freq2 < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Selected invalid VHT center freqs");
+ ret = -1;
+ goto out;
+ }
+
+ csa_settings.freq_params.vht_enabled = conf->ieee80211ac;
+ csa_settings.freq_params.center_freq1 = freq1;
+ csa_settings.freq_params.center_freq2 = freq2;
+
+ switch (conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ case VHT_CHANWIDTH_80P80MHZ:
+ csa_settings.freq_params.bandwidth = 80;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ csa_settings.freq_params.bandwidth = 160;
+ break;
+ }
+ }
+
+ ret = ap_switch_channel(wpa_s, &csa_settings);
+out:
+ current_ssid->frequency = old_freq;
+ hostapd_config_free(conf);
+ return ret;
}
@@ -8500,7 +8950,7 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
@@ -8537,6 +8987,13 @@ static void wpas_p2p_move_go(void *eloop_ctx, void *timeout_ctx)
wpas_p2p_go_update_common_freqs(wpa_s);
+ /* Do not move GO in the middle of a CSA */
+ if (hostapd_csa_in_progress(wpa_s->ap_iface)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: CSA is in progress - not moving GO");
+ return;
+ }
+
/*
* First, try a channel switch flow. If it is not supported or fails,
* take down the GO and bring it up again.
@@ -8613,6 +9070,25 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS &&
wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) {
policy_move = 1;
+ } else if ((wpa_s->conf->p2p_go_freq_change_policy ==
+ P2P_GO_FREQ_MOVE_SCM_ECSA) &&
+ wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) {
+ if (!p2p_get_group_num_members(wpa_s->p2p_group)) {
+ policy_move = 1;
+ } else if ((wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_AP_CSA) &&
+ wpas_p2p_go_clients_support_ecsa(wpa_s)) {
+ u8 chan;
+
+ /*
+ * We do not support CSA between bands, so move
+ * GO only within the same band.
+ */
+ if (wpa_s->ap_iface->current_mode->mode ==
+ ieee80211_freq_to_chan(freqs[i].freq,
+ &chan))
+ policy_move = 1;
+ }
}
}
@@ -8647,6 +9123,16 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
return;
}
+ /*
+ * Do not consider moving GO if it is in the middle of a CSA. When the
+ * CSA is finished this flow should be retriggered.
+ */
+ if (hostapd_csa_in_progress(wpa_s->ap_iface)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Not initiating a GO frequency change - CSA is in progress");
+ return;
+ }
+
if (invalid_freq && !wpas_p2p_disallowed_freq(wpa_s->global, freq))
timeout = P2P_GO_FREQ_CHANGE_TIME;
else
@@ -8726,3 +9212,86 @@ void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
wpas_p2p_group_deinit(wpa_s);
}
+
+
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ u8 *device_types;
+ size_t dev_types_len;
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->p2p_lo_started) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P Listen offload is already started");
+ return 0;
+ }
+
+ if (wpa_s->global->p2p == NULL ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
+ return -1;
+ }
+
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
+ freq);
+ return -1;
+ }
+
+ /* Get device type */
+ dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
+ WPS_DEV_TYPE_LEN;
+ device_types = os_malloc(dev_types_len);
+ if (!device_types)
+ return -1;
+ os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
+ os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
+ wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
+
+ /* Get Probe Response IE(s) */
+ buf = p2p_build_probe_resp_template(p2p, freq);
+ if (!buf) {
+ os_free(device_types);
+ return -1;
+ }
+
+ ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
+ device_types, dev_types_len,
+ wpabuf_mhead_u8(buf), wpabuf_len(buf));
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to start P2P listen offload");
+
+ os_free(device_types);
+ wpabuf_free(buf);
+
+ if (ret == 0) {
+ wpa_s->p2p_lo_started = 1;
+
+ /* Stop current P2P listen if any */
+ wpas_stop_listen(wpa_s);
+ }
+
+ return ret;
+}
+
+
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->p2p_lo_started)
+ return 0;
+
+ ret = wpa_drv_p2p_lo_stop(wpa_s);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to stop P2P listen offload");
+
+ wpa_s->p2p_lo_started = 0;
+ return ret;
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 56e6834..63910d1 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -34,17 +34,22 @@ struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s,
const u8 *peer_dev_addr);
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
- int persistent_group, int auto_join, int join,
- int auth, int go_intent, int freq, int persistent_id,
- int pd, int ht40, int vht);
+ int persistent_group, int auto_join, int join, int auth,
+ int go_intent, int freq, unsigned int vht_center_freq2,
+ int persistent_id, int pd, int ht40, int vht,
+ unsigned int vht_chwidth, const u8 *group_ssid,
+ size_t group_ssid_len);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq, int ht40, int vht);
+ int freq, int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int force_freq, int neg_freq, int ht40,
- int vht, const struct p2p_channels *channels,
+ int force_freq, int neg_freq,
+ int vht_center_freq2, int ht40,
+ int vht, int max_oper_chwidth,
+ const struct p2p_channels *channels,
int connection_timeout, int force_scan);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
@@ -111,7 +116,8 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40, int vht, int pref_freq);
+ int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int pref_freq);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
@@ -140,6 +146,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel);
int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel);
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
const u8 *p2p_dev_addr,
@@ -199,6 +207,10 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count);
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant/p2p_supplicant_sd.c
index fc07b07..f8675e6 100644
--- a/wpa_supplicant/p2p_supplicant_sd.c
+++ b/wpa_supplicant/p2p_supplicant_sd.c
@@ -48,7 +48,7 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
u8 *spos_tmp;
/* Offset */
- if (*spos + 2 > end) {
+ if (end - *spos < 2) {
wpa_printf(MSG_DEBUG, "P2P: No room for full "
"DNS offset field");
return -1;
@@ -74,14 +74,14 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
return 0;
(*spos)++;
- if (*spos + len > end) {
+ if (len > end - *spos) {
wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
"sequence - no room for label with length "
"%u", len);
return -1;
}
- if (*upos + len + 2 > uend)
+ if (len + 2 > uend - *upos)
return -2;
os_memcpy(*upos, *spos, len);
@@ -722,11 +722,11 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
if (resp == NULL)
return;
- while (pos + 1 < end) {
+ while (end - pos > 1) {
wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
"length");
wpabuf_free(resp);
@@ -827,10 +827,10 @@ static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
u8 svc_len;
/* Sanity check fixed length+svc_str */
- if (pos + 6 >= tlv_end)
+ if (6 >= tlv_end - pos)
break;
svc_len = pos[6];
- if (pos + svc_len + 10 > tlv_end)
+ if (svc_len + 10 > tlv_end - pos)
break;
/* Advertisement ID */
@@ -917,13 +917,13 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
}
}
- while (pos < end) {
+ while (end - pos >= 2) {
u8 srv_proto, srv_trans_id, status;
wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end || slen < 3) {
+ if (slen > end - pos || slen < 3) {
wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
"length");
return;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index d7049a1..fb8ebdf 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -36,8 +36,7 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
if (wpa_s->current_ssid == NULL) {
wpa_s->current_ssid = ssid;
- if (wpa_s->current_ssid != NULL)
- wpas_notify_network_changed(wpa_s);
+ wpas_notify_network_changed(wpa_s);
}
wpa_supplicant_initiate_eapol(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
@@ -60,10 +59,7 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
wps = 1;
*req_type = wpas_wps_get_req_type(ssid);
- if (!ssid->eap.phase1)
- continue;
-
- if (os_strstr(ssid->eap.phase1, "pbc=1"))
+ if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1"))
return 2;
}
@@ -166,6 +162,8 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
+ wpa_scan_free_params(params);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
radio_work_done(work);
return;
}
@@ -229,12 +227,11 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
}
ctx = wpa_scan_clone_params(params);
- if (ctx == NULL)
- return -1;
-
- if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+ if (!ctx ||
+ radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
{
wpa_scan_free_params(ctx);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
return -1;
}
@@ -266,14 +263,14 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- int interval)
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
{
int ret;
wpa_supplicant_notify_scanning(wpa_s, 1);
- ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+ ret = wpa_drv_sched_scan(wpa_s, params);
if (ret)
wpa_supplicant_notify_scanning(wpa_s, 0);
else
@@ -283,7 +280,7 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
}
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
{
int ret;
@@ -429,6 +426,39 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *default_ies = NULL;
+ u8 ext_capab[18];
+ int ext_capab_len;
+ enum wpa_driver_if_type type = WPA_IF_STATION;
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+ type = WPA_IF_P2P_CLIENT;
+#endif /* CONFIG_P2P */
+
+ wpa_drv_get_ext_capa(wpa_s, type);
+
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+ sizeof(ext_capab));
+ if (ext_capab_len > 0 &&
+ wpabuf_resize(&default_ies, ext_capab_len) == 0)
+ wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
+
+#ifdef CONFIG_MBO
+ /* Send cellular capabilities for potential MBO STAs */
+ if (wpabuf_resize(&default_ies, 9) == 0)
+ wpas_mbo_scan_ie(wpa_s, default_ies);
+#endif /* CONFIG_MBO */
+
+ if (default_ies)
+ wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
+ wpabuf_len(default_ies));
+ wpabuf_free(default_ies);
+}
+
+
static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *extra_ie = NULL;
@@ -439,6 +469,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+#endif /* CONFIG_P2P */
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
if (ext_capab_len > 0 &&
@@ -491,6 +528,19 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
#endif /* CONFIG_FST */
+#ifdef CONFIG_MBO
+ /* Send cellular capabilities for potential MBO STAs */
+ if (wpabuf_resize(&extra_ie, 9) == 0)
+ wpas_mbo_scan_ie(wpa_s, extra_ie);
+#endif /* CONFIG_MBO */
+
+ if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
+
+ if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
+ wpabuf_put_buf(extra_ie, buf);
+ }
+
return extra_ie;
}
@@ -522,21 +572,6 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_P2P */
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes,
- enum hostapd_hw_mode mode)
-{
- u16 i;
-
- for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
- return &modes[i];
- }
-
- return NULL;
-}
-
-
static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode band,
struct wpa_driver_scan_params *params)
@@ -586,6 +621,12 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
unsigned int i;
struct wpa_ssid *ssid;
+ /*
+ * For devices with max_ssids greater than 1, leave the last slot empty
+ * for adding the wildcard scan entry.
+ */
+ max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
+
for (i = 0; i < wpa_s->scan_id_count; i++) {
unsigned int j;
@@ -840,12 +881,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
* slot for the zero-terminator.
*/
params.freqs = os_malloc(sizeof(int) * 2);
- if (params.freqs == NULL) {
- wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed");
- return;
+ if (params.freqs) {
+ params.freqs[0] = wpa_s->assoc_freq;
+ params.freqs[1] = 0;
}
- params.freqs[0] = wpa_s->assoc_freq;
- params.freqs[1] = 0;
/*
* Reset the reattach flag so that we fall back to full scan if
@@ -1016,6 +1055,27 @@ ssid_list_set:
}
}
+ if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
+ struct wpa_bss *bss;
+
+ params.bssid = wpa_s->next_scan_bssid;
+ bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
+ if (bss && bss->ssid_len && params.num_ssids == 1 &&
+ params.ssids[0].ssid_len == 0) {
+ params.ssids[0].ssid = bss->ssid;
+ params.ssids[0].ssid_len = bss->ssid_len;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan a previously specified BSSID " MACSTR
+ " and SSID %s",
+ MAC2STR(params.bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan a previously specified BSSID " MACSTR,
+ MAC2STR(params.bssid));
+ }
+ }
+
scan_params = &params;
scan:
@@ -1076,6 +1136,8 @@ scan:
#ifdef CONFIG_INTERWORKING
wpa_s->interworking_fast_assoc_tried = 0;
#endif /* CONFIG_INTERWORKING */
+ if (params.bssid)
+ os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
}
}
@@ -1182,6 +1244,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
unsigned int max_sched_scan_ssids;
int wildcard = 0;
int need_ssids;
+ struct sched_scan_plan scan_plan;
if (!wpa_s->sched_scan_supported)
return -1;
@@ -1193,6 +1256,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
return -1;
+ wpa_s->sched_scan_stop_req = 0;
+
if (wpa_s->sched_scanning) {
wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
return 0;
@@ -1271,11 +1336,6 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (!ssid || !wpa_s->prev_sched_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
- if (wpa_s->conf->sched_scan_interval)
- wpa_s->sched_scan_interval =
- wpa_s->conf->sched_scan_interval;
- if (wpa_s->sched_scan_interval == 0)
- wpa_s->sched_scan_interval = 10;
wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
wpa_s->first_sched_scan = 1;
ssid = wpa_s->conf->ssid;
@@ -1360,14 +1420,51 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
scan_params = &params;
scan:
- if (ssid || !wpa_s->first_sched_scan) {
+ wpa_s->sched_scan_timed_out = 0;
+
+ /*
+ * We cannot support multiple scan plans if the scan request includes
+ * too many SSID's, so in this case use only the last scan plan and make
+ * it run infinitely. It will be stopped by the timeout.
+ */
+ if (wpa_s->sched_scan_plans_num == 1 ||
+ (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) {
+ params.sched_scan_plans = wpa_s->sched_scan_plans;
+ params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
+ } else if (wpa_s->sched_scan_plans_num > 1) {
wpa_dbg(wpa_s, MSG_DEBUG,
- "Starting sched scan: interval %d timeout %d",
- wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+ "Too many SSIDs. Default to using single scheduled_scan plan");
+ params.sched_scan_plans =
+ &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num -
+ 1];
+ params.sched_scan_plans_num = 1;
} else {
+ if (wpa_s->conf->sched_scan_interval)
+ scan_plan.interval = wpa_s->conf->sched_scan_interval;
+ else
+ scan_plan.interval = 10;
+
+ if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) {
+ wpa_printf(MSG_WARNING,
+ "Scan interval too long(%u), use the maximum allowed(%u)",
+ scan_plan.interval,
+ wpa_s->max_sched_scan_plan_interval);
+ scan_plan.interval =
+ wpa_s->max_sched_scan_plan_interval;
+ }
+
+ scan_plan.iterations = 0;
+ params.sched_scan_plans = &scan_plan;
+ params.sched_scan_plans_num = 1;
+ }
+
+ if (ssid || !wpa_s->first_sched_scan) {
wpa_dbg(wpa_s, MSG_DEBUG,
- "Starting sched scan: interval %d (no timeout)",
- wpa_s->sched_scan_interval);
+ "Starting sched scan: interval %u timeout %d",
+ params.sched_scan_plans[0].interval,
+ wpa_s->sched_scan_timeout);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan (no timeout)");
}
wpa_setband_scan_freqs(wpa_s, scan_params);
@@ -1381,8 +1478,7 @@ scan:
}
}
- ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
- wpa_s->sched_scan_interval);
+ ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
if (ret) {
@@ -1400,9 +1496,12 @@ scan:
wpa_s, NULL);
wpa_s->first_sched_scan = 0;
wpa_s->sched_scan_timeout /= 2;
- wpa_s->sched_scan_interval *= 2;
- if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) {
- wpa_s->sched_scan_interval = 10;
+ params.sched_scan_plans[0].interval *= 2;
+ if ((unsigned int) wpa_s->sched_scan_timeout <
+ params.sched_scan_plans[0].interval ||
+ params.sched_scan_plans[0].interval >
+ wpa_s->max_sched_scan_plan_interval) {
+ params.sched_scan_plans[0].interval = 10;
wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
}
}
@@ -1457,6 +1556,9 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
if (!wpa_s->sched_scanning)
return;
+ if (wpa_s->sched_scanning)
+ wpa_s->sched_scan_stop_req = 1;
+
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
wpa_supplicant_stop_sched_scan(wpa_s);
@@ -1516,20 +1618,7 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
*/
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
{
- const u8 *end, *pos;
-
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
+ return get_ie((const u8 *) (res + 1), res->ie_len, ie);
}
@@ -1550,8 +1639,8 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
pos = (const u8 *) (res + 1);
end = pos + res->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1587,8 +1676,8 @@ const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
pos += res->ie_len;
end = pos + res->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1623,8 +1712,8 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
pos = (const u8 *) (res + 1);
end = pos + res->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1832,8 +1921,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
}
-static void filter_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *res)
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res)
{
size_t i, j;
@@ -1860,13 +1949,13 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s,
/*
* Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurments. These values were
+ * measurements, but no noise floor measurements. These values were
* measured in an office environment with many APs.
*/
#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-static void scan_snr(struct wpa_scan_res *res)
+void scan_snr(struct wpa_scan_res *res)
{
if (res->flags & WPA_SCAN_NOISE_INVALID) {
res->noise = IS_5GHZ(res->freq) ?
@@ -1950,8 +2039,8 @@ static unsigned int max_vht80_rate(int snr)
}
-static void scan_est_throughput(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
{
enum local_hw_capab capab = wpa_s->hw_capab;
int rate; /* max legacy rate in 500 kb/s units */
@@ -2148,6 +2237,9 @@ void scan_only_handler(struct wpa_supplicant *wpa_s,
wpa_s->scan_work = NULL;
radio_work_done(work);
}
+
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
}
@@ -2214,6 +2306,19 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->only_new_results = src->only_new_results;
params->low_priority = src->low_priority;
+ if (src->sched_scan_plans_num > 0) {
+ params->sched_scan_plans =
+ os_malloc(sizeof(*src->sched_scan_plans) *
+ src->sched_scan_plans_num);
+ if (!params->sched_scan_plans)
+ goto failed;
+
+ os_memcpy(params->sched_scan_plans, src->sched_scan_plans,
+ sizeof(*src->sched_scan_plans) *
+ src->sched_scan_plans_num);
+ params->sched_scan_plans_num = src->sched_scan_plans_num;
+ }
+
if (src->mac_addr_rand) {
params->mac_addr_rand = src->mac_addr_rand;
@@ -2231,6 +2336,17 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->mac_addr_mask = mac_addr + ETH_ALEN;
}
}
+
+ if (src->bssid) {
+ u8 *bssid;
+
+ bssid = os_malloc(ETH_ALEN);
+ if (!bssid)
+ goto failed;
+ os_memcpy(bssid, src->bssid, ETH_ALEN);
+ params->bssid = bssid;
+ }
+
return params;
failed:
@@ -2251,6 +2367,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
os_free((u8 *) params->extra_ies);
os_free(params->freqs);
os_free(params->filter_ssids);
+ os_free(params->sched_scan_plans);
/*
* Note: params->mac_addr_mask points to same memory allocation and
@@ -2258,20 +2375,31 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
*/
os_free((u8 *) params->mac_addr);
+ os_free((u8 *) params->bssid);
+
os_free(params);
}
int wpas_start_pno(struct wpa_supplicant *wpa_s)
{
- int ret, interval, prio;
+ int ret, prio;
size_t i, num_ssid, num_match_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
+ struct sched_scan_plan scan_plan;
+ unsigned int max_sched_scan_ssids;
if (!wpa_s->sched_scan_supported)
return -1;
+ if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+ max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+ else
+ max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+ if (max_sched_scan_ssids < 1)
+ return -1;
+
if (wpa_s->pno || wpa_s->pno_sched_pending)
return 0;
@@ -2292,6 +2420,13 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
}
+ if (wpa_s->sched_scan_stop_req) {
+ wpa_printf(MSG_DEBUG,
+ "Schedule PNO after previous sched scan has stopped");
+ wpa_s->pno_sched_pending = 1;
+ return 0;
+ }
+
os_memset(&params, 0, sizeof(params));
num_ssid = num_match_ssid = 0;
@@ -2315,10 +2450,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
num_ssid++;
}
- if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+ if (num_ssid > max_sched_scan_ssids) {
wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
- "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
- num_ssid = WPAS_MAX_SCAN_SSIDS;
+ "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
+ num_ssid = max_sched_scan_ssids;
}
if (num_match_ssid > wpa_s->max_match_sets) {
@@ -2361,8 +2496,20 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->filter_rssi)
params.filter_rssi = wpa_s->conf->filter_rssi;
- interval = wpa_s->conf->sched_scan_interval ?
- wpa_s->conf->sched_scan_interval : 10;
+ if (wpa_s->sched_scan_plans_num) {
+ params.sched_scan_plans = wpa_s->sched_scan_plans;
+ params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
+ } else {
+ /* Set one scan plan that will run infinitely */
+ if (wpa_s->conf->sched_scan_interval)
+ scan_plan.interval = wpa_s->conf->sched_scan_interval;
+ else
+ scan_plan.interval = 10;
+
+ scan_plan.iterations = 0;
+ params.sched_scan_plans = &scan_plan;
+ params.sched_scan_plans_num = 1;
+ }
if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels");
@@ -2377,7 +2524,7 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
}
- ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
+ ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
os_free(params.filter_ssids);
if (ret == 0)
wpa_s->pno = 1;
@@ -2395,6 +2542,7 @@ int wpas_stop_pno(struct wpa_supplicant *wpa_s)
return 0;
ret = wpa_supplicant_stop_sched_scan(wpa_s);
+ wpa_s->sched_scan_stop_req = 1;
wpa_s->pno = 0;
wpa_s->pno_sched_pending = 0;
@@ -2462,3 +2610,160 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
wpa_s->mac_addr_rand_enable |= type;
return 0;
}
+
+
+int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
+{
+ int scan_work = !!wpa_s->scan_work;
+
+#ifdef CONFIG_P2P
+ scan_work |= !!wpa_s->p2p_scan_work;
+#endif /* CONFIG_P2P */
+
+ if (scan_work && wpa_s->own_scan_running) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
+ return wpa_drv_abort_scan(wpa_s);
+ }
+
+ return 0;
+}
+
+
+int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct sched_scan_plan *scan_plans = NULL;
+ const char *token, *context = NULL;
+ unsigned int num = 0;
+
+ if (!cmd)
+ return -1;
+
+ if (!cmd[0]) {
+ wpa_printf(MSG_DEBUG, "Clear sched scan plans");
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = NULL;
+ wpa_s->sched_scan_plans_num = 0;
+ return 0;
+ }
+
+ while ((token = cstr_token(cmd, " ", &context))) {
+ int ret;
+ struct sched_scan_plan *scan_plan, *n;
+
+ n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans));
+ if (!n)
+ goto fail;
+
+ scan_plans = n;
+ scan_plan = &scan_plans[num];
+ num++;
+
+ ret = sscanf(token, "%u:%u", &scan_plan->interval,
+ &scan_plan->iterations);
+ if (ret <= 0 || ret > 2 || !scan_plan->interval) {
+ wpa_printf(MSG_ERROR,
+ "Invalid sched scan plan input: %s", token);
+ goto fail;
+ }
+
+ if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
+ wpa_printf(MSG_WARNING,
+ "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
+ num, scan_plan->interval,
+ wpa_s->max_sched_scan_plan_interval);
+ scan_plan->interval =
+ wpa_s->max_sched_scan_plan_interval;
+ }
+
+ if (ret == 1) {
+ scan_plan->iterations = 0;
+ break;
+ }
+
+ if (!scan_plan->iterations) {
+ wpa_printf(MSG_ERROR,
+ "scan plan %u: Number of iterations cannot be zero",
+ num);
+ goto fail;
+ }
+
+ if (scan_plan->iterations >
+ wpa_s->max_sched_scan_plan_iterations) {
+ wpa_printf(MSG_WARNING,
+ "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)",
+ num, scan_plan->iterations,
+ wpa_s->max_sched_scan_plan_iterations);
+ scan_plan->iterations =
+ wpa_s->max_sched_scan_plan_iterations;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "scan plan %u: interval=%u iterations=%u",
+ num, scan_plan->interval, scan_plan->iterations);
+ }
+
+ if (!scan_plans) {
+ wpa_printf(MSG_ERROR, "Invalid scan plans entry");
+ goto fail;
+ }
+
+ if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) {
+ wpa_printf(MSG_ERROR,
+ "All scan plans but the last must specify a number of iterations");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u",
+ num, scan_plans[num - 1].interval);
+
+ if (num > wpa_s->max_sched_scan_plans) {
+ wpa_printf(MSG_WARNING,
+ "Too many scheduled scan plans (only %u supported)",
+ wpa_s->max_sched_scan_plans);
+ wpa_printf(MSG_WARNING,
+ "Use only the first %u scan plans, and the last one (in infinite loop)",
+ wpa_s->max_sched_scan_plans - 1);
+ os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1],
+ &scan_plans[num - 1], sizeof(*scan_plans));
+ num = wpa_s->max_sched_scan_plans;
+ }
+
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = scan_plans;
+ wpa_s->sched_scan_plans_num = num;
+
+ return 0;
+
+fail:
+ os_free(scan_plans);
+ wpa_printf(MSG_ERROR, "invalid scan plans list");
+ return -1;
+}
+
+
+/**
+ * wpas_scan_reset_sched_scan - Reset sched_scan state
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a running scheduled scan and to reset an
+ * internal scan state to continue with a regular scan on the following
+ * wpa_supplicant_req_scan() calls.
+ */
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->normal_scans = 0;
+ if (wpa_s->sched_scanning) {
+ wpa_s->sched_scan_timed_out = 0;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ }
+}
+
+
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ /* simulate timeout to restart the sched scan */
+ wpa_s->sched_scan_timed_out = 1;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 7650f5a..2aa0a8b 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -39,20 +39,25 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec);
void scan_only_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- int interval);
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s);
struct wpa_driver_scan_params *
wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
void wpa_scan_free_params(struct wpa_driver_scan_params *params);
int wpas_start_pno(struct wpa_supplicant *wpa_s);
int wpas_stop_pno(struct wpa_supplicant *wpa_s);
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s);
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s);
void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
unsigned int type);
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res);
+void scan_snr(struct wpa_scan_res *res);
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res);
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index f2e5a43..61fd3b2 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -161,9 +161,10 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
return;
}
- if (!(wpa_s->drv_rrm_flags &
- WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
- !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) {
+ if (!((wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+ (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+ !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) {
wpa_printf(MSG_DEBUG,
"RRM: Insufficient RRM support in driver - do not use RRM");
return;
@@ -186,6 +187,9 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+ if (wpa_s->lci)
+ pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT;
+
wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
wpa_s->rrm.rrm_used = 1;
}
@@ -208,6 +212,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
u8 ext_capab[18];
int ext_capab_len;
int skip_auth;
+#ifdef CONFIG_MBO
+ const u8 *mbo;
+#endif /* CONFIG_MBO */
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -416,28 +423,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_HS20
- if (is_hs20_network(wpa_s, ssid, bss)) {
- struct wpabuf *hs20;
- hs20 = wpabuf_alloc(20);
- if (hs20) {
- int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
- size_t len;
-
- wpas_hs20_add_indication(hs20, pps_mo_id);
- len = sizeof(wpa_s->sme.assoc_req_ie) -
- wpa_s->sme.assoc_req_ie_len;
- if (wpabuf_len(hs20) <= len) {
- os_memcpy(wpa_s->sme.assoc_req_ie +
- wpa_s->sme.assoc_req_ie_len,
- wpabuf_head(hs20), wpabuf_len(hs20));
- wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
- }
- wpabuf_free(hs20);
- }
- }
-#endif /* CONFIG_HS20 */
-
#ifdef CONFIG_FST
if (wpa_s->fst_ies) {
int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
@@ -453,6 +438,28 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_FST */
+ sme_auth_handle_rrm(wpa_s, bss);
+
+#ifdef CONFIG_MBO
+ mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (mbo) {
+ int len;
+
+ len = wpas_mbo_supp_op_class_ie(
+ wpa_s, bss->freq,
+ wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len);
+ if (len > 0)
+ wpa_s->sme.assoc_req_ie_len += len;
+ }
+#endif /* CONFIG_MBO */
+
+ if (params.p2p)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
if (ext_capab_len > 0) {
@@ -466,6 +473,29 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+#ifdef CONFIG_HS20
+ if (is_hs20_network(wpa_s, ssid, bss)) {
+ struct wpabuf *hs20;
+
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+ size_t len;
+
+ wpas_hs20_add_indication(hs20, pps_mo_id);
+ len = sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+ if (wpabuf_len(hs20) <= len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(hs20), wpabuf_len(hs20));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
+ }
+ wpabuf_free(hs20);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
size_t len;
@@ -480,7 +510,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
}
- sme_auth_handle_rrm(wpa_s, bss);
+#ifdef CONFIG_MBO
+ if (mbo) {
+ int len;
+
+ len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len);
+ if (len >= 0)
+ wpa_s->sme.assoc_req_ie_len += len;
+ }
+#endif /* CONFIG_MBO */
#ifdef CONFIG_SAE
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
@@ -524,6 +565,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+
#ifdef CONFIG_P2P
/*
* If multi-channel concurrency is not supported, check for any
@@ -632,6 +677,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
radio_remove_works(wpa_s, "sme-connect", 0);
}
+ wpas_abort_ongoing_scan(wpa_s);
+
cwork = os_zalloc(sizeof(*cwork));
if (cwork == NULL)
return;
@@ -812,7 +859,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
"4-way handshake");
wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->pending_bssid);
+ wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
}
#endif /* CONFIG_SAE */
@@ -975,8 +1022,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
params.p2p = 1;
- if (wpa_s->parent->set_sta_uapsd)
- params.uapsd = wpa_s->parent->sta_uapsd;
+ if (wpa_s->p2pdev->set_sta_uapsd)
+ params.uapsd = wpa_s->p2pdev->sta_uapsd;
else
params.uapsd = -1;
@@ -1320,21 +1367,6 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
}
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes,
- enum hostapd_hw_mode mode)
-{
- u16 i;
-
- for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
- return &modes[i];
- }
-
- return NULL;
-}
-
-
static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
@@ -1553,8 +1585,10 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
wpa_s->sme.sa_query_count + 1,
WLAN_SA_QUERY_TR_ID_LEN);
- if (nbuf == NULL)
+ if (nbuf == NULL) {
+ sme_stop_sa_query(wpa_s);
return;
+ }
if (wpa_s->sme.sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_reltime(&wpa_s->sme.sa_query_start);
@@ -1565,6 +1599,7 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+ sme_stop_sa_query(wpa_s);
return;
}
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
index ea964ce..bc5d49a 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -5,9 +5,9 @@ Wants=network.target
[Service]
Type=dbus
-BusName=fi.epitest.hostap.WPASupplicant
+BusName=@DBUS_INTERFACE@
ExecStart=@BINDIR@/wpa_supplicant -u
[Install]
WantedBy=multi-user.target
-Alias=dbus-fi.epitest.hostap.WPASupplicant.service
+Alias=dbus-@DBUS_INTERFACE@.service
diff --git a/wpa_supplicant/tests/link_test.c b/wpa_supplicant/tests/link_test.c
deleted file mode 100644
index 3bfbed5..0000000
--- a/wpa_supplicant/tests/link_test.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Dummy functions to allow link_test to be linked. The need for these
- * functions should be removed to allow IEEE 802.1X/EAPOL authenticator to
- * be built outside hostapd.
- */
-
-#include "includes.h"
-
-#include "common.h"
-
-
-struct hostapd_data;
-struct sta_info;
-struct rsn_pmksa_cache_entry;
-struct eapol_state_machine;
-struct hostapd_eap_user;
-struct hostapd_bss_config;
-struct hostapd_vlan;
-
-
-struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
-{
- return NULL;
-}
-
-
-int ap_for_each_sta(struct hostapd_data *hapd,
- int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
- void *ctx),
- void *ctx)
-{
- return 0;
-}
-
-
-void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
- u32 session_timeout)
-{
-}
-
-
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
- int old_vlanid)
-{
- return 0;
-}
-
-
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
- int success)
-{
-}
-
-
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
- u8 *buf, size_t len)
-{
-}
-
-
-void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
-{
-}
-
-
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
- struct eapol_state_machine *eapol)
-{
-}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2)
-{
- return NULL;
-}
-
-
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
-{
- return NULL;
-}
diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c
deleted file mode 100644
index f60b182..0000000
--- a/wpa_supplicant/tests/test_eap_sim_common.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Test program for EAP-SIM PRF
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "eap_common/eap_sim_common.c"
-
-
-static int test_eap_sim_prf(void)
-{
- /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
- u8 xkey[] = {
- 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
- 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
- 0xeb, 0x5a, 0x38, 0xb6
- };
- u8 w[] = {
- 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
- 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
- 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
- 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
- 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
- };
- u8 buf[40];
-
- printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
- eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w)) != 0) {
- printf("eap_sim_prf failed\n");
- return 1;
- }
-
- return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
- int errors = 0;
-
- errors += test_eap_sim_prf();
-
- return errors;
-}
diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c
deleted file mode 100644
index 39971f2..0000000
--- a/wpa_supplicant/tests/test_wpa.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Test program for combined WPA authenticator/supplicant
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "../config.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/wpa_ie.h"
-#include "ap/wpa_auth.h"
-
-
-struct wpa {
- u8 auth_addr[ETH_ALEN];
- u8 supp_addr[ETH_ALEN];
- u8 psk[PMK_LEN];
-
- /* from authenticator */
- u8 auth_eapol_dst[ETH_ALEN];
- u8 *auth_eapol;
- size_t auth_eapol_len;
-
- /* from supplicant */
- u8 *supp_eapol;
- size_t supp_eapol_len;
-
- struct wpa_sm *supp;
- struct wpa_authenticator *auth_group;
- struct wpa_state_machine *auth;
-
- struct wpa_ssid ssid;
- u8 supp_ie[80];
- size_t supp_ie_len;
-};
-
-
-static int supp_get_bssid(void *ctx, u8 *bssid)
-{
- struct wpa *wpa = ctx;
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
- os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
- return 0;
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
-}
-
-
-static void auth_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
- wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
- wpa->supp_eapol_len);
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
- size_t len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
-
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = os_malloc(len);
- if (wpa->supp_eapol == NULL)
- return -1;
- os_memcpy(wpa->supp_eapol, buf, len);
- wpa->supp_eapol_len = len;
- eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
- u16 data_len, size_t *msg_len, void **data_pos)
-{
- struct ieee802_1x_hdr *hdr;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
- __func__, type, data_len);
-
- *msg_len = sizeof(*hdr) + data_len;
- hdr = os_malloc(*msg_len);
- if (hdr == NULL)
- return NULL;
-
- hdr->version = 2;
- hdr->type = type;
- hdr->length = host_to_be16(data_len);
-
- if (data)
- os_memcpy(hdr + 1, data, data_len);
- else
- os_memset(hdr + 1, 0, data_len);
-
- if (data_pos)
- *data_pos = hdr + 1;
-
- return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
- struct wpa *wpa = ctx;
- const u8 *ie;
- size_t ielen;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-
- ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
- if (ie == NULL || ielen < 1)
- return -1;
- if (ie[0] == WLAN_EID_RSN)
- return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
- return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
-}
-
-
-static int supp_set_key(void *ctx, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
- "set_tx=%d)",
- __func__, alg, MAC2STR(addr), key_idx, set_tx);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
- return 0;
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
- int protection_type, int key_type)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
- "key_type=%d)",
- __func__, MAC2STR(addr), protection_type, key_type);
- return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-static int supp_init(struct wpa *wpa)
-{
- struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return -1;
-
- ctx->ctx = wpa;
- ctx->msg_ctx = wpa;
- ctx->set_state = supp_set_state;
- ctx->get_bssid = supp_get_bssid;
- ctx->ether_send = supp_ether_send;
- ctx->get_beacon_ie = supp_get_beacon_ie;
- ctx->alloc_eapol = supp_alloc_eapol;
- ctx->set_key = supp_set_key;
- ctx->mlme_setprotection = supp_mlme_setprotection;
- ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
- wpa->supp = wpa_sm_init(ctx);
- if (wpa->supp == NULL) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
- return -1;
- }
-
- wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
- wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN);
-
- wpa->supp_ie_len = sizeof(wpa->supp_ie);
- if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
- &wpa->supp_ie_len) < 0) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
- " failed");
- return -1;
- }
-
- wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
-
- return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
- const char *txt)
-{
- if (addr)
- wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
- MAC2STR(addr), txt);
- else
- wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static void supp_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
- wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
- wpa->auth_eapol_len);
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
- size_t data_len, int encrypt)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
- "encrypt=%d)",
- __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
-
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = os_malloc(data_len);
- if (wpa->auth_eapol == NULL)
- return -1;
- os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN);
- os_memcpy(wpa->auth_eapol, data, data_len);
- wpa->auth_eapol_len = data_len;
- eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
-{
- struct wpa *wpa = ctx;
- wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
- __func__, MAC2STR(addr), prev_psk);
- if (prev_psk)
- return NULL;
- return wpa->psk;
-}
-
-
-static int auth_init_group(struct wpa *wpa)
-{
- struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
-
- wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
- os_memset(&conf, 0, sizeof(conf));
- conf.wpa = 2;
- conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
- conf.eapol_version = 2;
-
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = wpa;
- cb.logger = auth_logger;
- cb.send_eapol = auth_send_eapol;
- cb.get_psk = auth_get_psk;
-
- wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb);
- if (wpa->auth_group == NULL) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
- return -1;
- }
-
- return 0;
-}
-
-
-static int auth_init(struct wpa *wpa)
-{
- wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
- if (wpa->auth == NULL) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
- return -1;
- }
-
- if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
- wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
- return -1;
- }
-
- wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
-
- wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
-
- return 0;
-}
-
-
-static void deinit(struct wpa *wpa)
-{
- wpa_auth_sta_deinit(wpa->auth);
- wpa_sm_deinit(wpa->supp);
- wpa_deinit(wpa->auth_group);
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = NULL;
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = NULL;
-}
-
-
-int main(int argc, char *argv[])
-{
- struct wpa wpa;
-
- if (os_program_init())
- return -1;
-
- os_memset(&wpa, 0, sizeof(wpa));
- os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
- os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
- os_memset(wpa.psk, 0x44, PMK_LEN);
-
- wpa_debug_level = 0;
- wpa_debug_show_keys = 1;
-
- if (eloop_init()) {
- wpa_printf(MSG_ERROR, "Failed to initialize event loop");
- return -1;
- }
-
- if (auth_init_group(&wpa) < 0)
- return -1;
-
- if (supp_init(&wpa) < 0)
- return -1;
-
- if (auth_init(&wpa) < 0)
- return -1;
-
- wpa_printf(MSG_DEBUG, "Starting eloop");
- eloop_run();
- wpa_printf(MSG_DEBUG, "eloop done");
-
- deinit(&wpa);
-
- eloop_destroy();
-
- os_program_deinit();
-
- return 0;
-}
diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h
index 5171b16..0d15ad0 100644
--- a/wpa_supplicant/wmm_ac.h
+++ b/wpa_supplicant/wmm_ac.h
@@ -88,7 +88,7 @@ enum ts_dir_idx {
*/
struct wmm_ac_addts_request {
/*
- * dialog token - Used to link the recived ADDTS response with this
+ * dialog token - Used to link the received ADDTS response with this
* saved ADDTS request when ADDTS response is being handled
*/
u8 dialog_token;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 954de67..1b3409c 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -24,6 +24,7 @@
#define MAX_TFS_IE_LEN 1024
#define WNM_MAX_NEIGHBOR_REPORT 10
+#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
@@ -37,12 +38,14 @@ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
/* set the TFS IE to driver */
static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
- const u8 *addr, u8 *buf, u16 *buf_len,
+ const u8 *addr, const u8 *buf, u16 buf_len,
enum wnm_oper oper)
{
+ u16 len = buf_len;
+
wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
- return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+ return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
}
@@ -137,6 +140,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
if (res < 0)
wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
"(action=%d, intval=%d)", action, intval);
+ else
+ wpa_s->wnmsleep_used = 1;
os_free(wnmsleep_ie);
os_free(wnmtfs_ie);
@@ -147,8 +152,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
- u8 *tfsresp_ie_start,
- u8 *tfsresp_ie_end)
+ const u8 *tfsresp_ie_start,
+ const u8 *tfsresp_ie_end)
{
wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
wpa_s->bssid, NULL, NULL);
@@ -164,7 +169,7 @@ static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
/* pass the TFS Resp IE(s) to driver for processing */
if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
tfsresp_ie_start,
- &tfsresp_ie_len,
+ tfsresp_ie_len,
WNM_SLEEP_TFS_RESP_IE_SET))
wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
}
@@ -187,8 +192,14 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
end = ptr + key_len_total;
wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
- while (ptr + 1 < end) {
- if (ptr + 2 + ptr[1] > end) {
+ if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled");
+ return;
+ }
+
+ while (end - ptr > 1) {
+ if (2 + ptr[1] > end - ptr) {
wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
"length");
if (end > ptr) {
@@ -239,14 +250,20 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
* Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
* WNM-Sleep Mode IE | TFS Response IE
*/
- u8 *pos = (u8 *) frm; /* point to payload after the action field */
+ const u8 *pos = frm; /* point to payload after the action field */
u16 key_len_total;
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Resp IE (assuming consecutive) */
- u8 *tfsresp_ie_start = NULL;
- u8 *tfsresp_ie_end = NULL;
+ const u8 *tfsresp_ie_start = NULL;
+ const u8 *tfsresp_ie_end = NULL;
size_t left;
+ if (!wpa_s->wnmsleep_used) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
+ return;
+ }
+
if (len < 3)
return;
key_len_total = WPA_GET_LE16(frm + 1);
@@ -259,14 +276,14 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
return;
}
pos += 3 + key_len_total;
- while (pos - frm < len) {
+ while (pos - frm + 1 < len) {
u8 ie_len = *(pos + 1);
- if (pos + 2 + ie_len > frm + len) {
+ if (2 + ie_len > frm + len - pos) {
wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
break;
}
wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
- if (*pos == WLAN_EID_WNMSLEEP)
+ if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_RESP) {
if (!tfsresp_ie_start)
@@ -413,6 +430,7 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
{
struct wpa_bss *bss = wpa_s->current_bss;
const char *country = NULL;
+ int freq;
if (bss) {
const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
@@ -421,7 +439,21 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
country = (const char *) (elem + 2);
}
- return ieee80211_chan_to_freq(country, op_class, chan);
+ freq = ieee80211_chan_to_freq(country, op_class, chan);
+ if (freq <= 0 && op_class == 0) {
+ /*
+ * Some APs do not advertise correct operating class
+ * information. Try to determine the most likely operating
+ * frequency based on the channel number.
+ */
+ if (chan >= 1 && chan <= 13)
+ freq = 2407 + chan * 5;
+ else if (chan == 14)
+ freq = 2484;
+ else if (chan >= 36 && chan <= 169)
+ freq = 5000 + chan * 5;
+ }
+ return freq;
}
@@ -468,7 +500,7 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs)
{
u8 i;
@@ -476,7 +508,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
struct wpa_bss *target;
if (!bss)
- return 0;
+ return NULL;
wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
MAC2STR(wpa_s->bssid), bss->level);
@@ -501,6 +533,19 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
continue;
}
+ if (age_secs) {
+ struct os_reltime now;
+
+ if (os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &target->last_update,
+ age_secs)) {
+ wpa_printf(MSG_DEBUG,
+ "Candidate BSS is more than %ld seconds old",
+ age_secs);
+ continue;
+ }
+ }
+
if (bss->ssid_len != target->ssid_len ||
os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
/*
@@ -515,6 +560,25 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
continue;
}
+ if (wpa_s->current_ssid &&
+ !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
+ 1)) {
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) does not match the current network profile",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ continue;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Candidate BSS " MACSTR
+ " retry delay is not over yet",
+ MAC2STR(nei->bssid));
+ continue;
+ }
+
if (target->level < bss->level && target->level < -80) {
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
" (pref %d) does not have sufficient signal level (%d)",
@@ -536,12 +600,190 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
}
+static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
+{
+ const u8 *ie_a, *ie_b;
+
+ if (!a || !b)
+ return 0;
+
+ ie_a = wpa_bss_get_ie(a, eid);
+ ie_b = wpa_bss_get_ie(b, eid);
+
+ if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
+ return 0;
+
+ return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
+}
+
+
+static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ u32 info = 0;
+
+ info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
+
+ /*
+ * Leave the security and key scope bits unset to indicate that the
+ * security information is not available.
+ */
+
+ if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+ if (bss->caps & WLAN_CAPABILITY_QOS)
+ info |= NEI_REP_BSSID_INFO_QOS;
+ if (bss->caps & WLAN_CAPABILITY_APSD)
+ info |= NEI_REP_BSSID_INFO_APSD;
+ if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
+ info |= NEI_REP_BSSID_INFO_RM;
+ if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
+ info |= NEI_REP_BSSID_INFO_DELAYED_BA;
+ if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
+ info |= NEI_REP_BSSID_INFO_IMM_BA;
+ if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
+ info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
+ if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
+ info |= NEI_REP_BSSID_INFO_HT;
+
+ return info;
+}
+
+
+static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info,
+ u8 op_class, u8 chan, u8 phy_type, u8 pref)
+{
+ u8 *pos = buf;
+
+ if (len < 18) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Not enough room for Neighbor Report element");
+ return -1;
+ }
+
+ *pos++ = WLAN_EID_NEIGHBOR_REPORT;
+ /* length: 13 for basic neighbor report + 3 for preference subelement */
+ *pos++ = 16;
+ os_memcpy(pos, bssid, ETH_ALEN);
+ pos += ETH_ALEN;
+ WPA_PUT_LE32(pos, bss_info);
+ pos += 4;
+ *pos++ = op_class;
+ *pos++ = chan;
+ *pos++ = phy_type;
+ *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE;
+ *pos++ = 1;
+ *pos++ = pref;
+ return pos - buf;
+}
+
+
+static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, u8 *buf, size_t len,
+ u8 pref)
+{
+ const u8 *ie;
+ u8 op_class, chan;
+ int sec_chan = 0, vht = 0;
+ enum phy_type phy_type;
+ u32 info;
+ struct ieee80211_ht_operation *ht_oper = NULL;
+ struct ieee80211_vht_operation *vht_oper = NULL;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2) {
+ ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+
+ if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ sec_chan = 1;
+ else if (ht_oper->ht_param &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ sec_chan = -1;
+ }
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= 1) {
+ vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+ if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
+ vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
+ vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ vht = vht_oper->vht_op_info_chwidth;
+ }
+
+ if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
+ &chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Cannot determine operating class and channel");
+ return -2;
+ }
+
+ phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
+ (vht_oper != NULL));
+ if (phy_type == PHY_TYPE_UNSPECIFIED) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Cannot determine BSS phy type for Neighbor Report");
+ return -2;
+ }
+
+ info = wnm_get_bss_info(wpa_s, bss);
+
+ return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan,
+ phy_type, pref);
+}
+
+
+static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+ unsigned int i, pref = 255;
+ struct os_reltime now;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (!ssid)
+ return 0;
+
+ /*
+ * TODO: Define when scan results are no longer valid for the candidate
+ * list.
+ */
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
+ return 0;
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Add candidate list to BSS Transition Management Response frame");
+ for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
+ int res;
+
+ if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
+ res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
+ if (res == -2)
+ continue; /* could not build entry for BSS */
+ if (res < 0)
+ break; /* no more room for candidates */
+ if (pref == 1)
+ break;
+
+ pos += res;
+ len -= res;
+ }
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "WNM: BSS Transition Management Response candidate list",
+ buf, pos - buf);
+
+ return pos - buf;
+}
+
+
static void wnm_send_bss_transition_mgmt_resp(
struct wpa_supplicant *wpa_s, u8 dialog_token,
enum bss_trans_mgmt_status_code status, u8 delay,
const u8 *target_bssid)
{
- u8 buf[1000], *pos;
+ u8 buf[2000], *pos;
struct ieee80211_mgmt *mgmt;
size_t len;
int res;
@@ -581,6 +823,17 @@ static void wnm_send_bss_transition_mgmt_resp(
pos += ETH_ALEN;
}
+ if (status == WNM_BSS_TM_ACCEPT)
+ pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
+#ifdef CONFIG_MBO
+ if (status != WNM_BSS_TM_ACCEPT) {
+ pos += wpas_mbo_ie_bss_trans_reject(
+ wpa_s, pos, buf + sizeof(buf) - pos,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED);
+ }
+#endif /* CONFIG_MBO */
+
len = pos - (u8 *) &mgmt->u.action.category;
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -593,6 +846,41 @@ static void wnm_send_bss_transition_mgmt_resp(
}
+static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ int after_new_scan)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Transition to BSS " MACSTR
+ " based on BSS Transition Management Request (old BSSID "
+ MACSTR " after_new_scan=%d)",
+ MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan);
+
+ /* Send the BSS Management Response - Accept */
+ if (wpa_s->wnm_reply) {
+ wpa_s->wnm_reply = 0;
+ wpa_printf(MSG_DEBUG,
+ "WNM: Sending successful BSS Transition Management Response");
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ WNM_BSS_TM_ACCEPT,
+ 0, bss->bssid);
+ }
+
+ if (bss == wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Already associated with the preferred candidate");
+ wnm_deallocate_memory(wpa_s);
+ return;
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ wnm_deallocate_memory(wpa_s);
+}
+
+
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
{
struct wpa_bss *bss;
@@ -602,6 +890,8 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
if (!wpa_s->wnm_neighbor_report_elements)
return 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Process scan results for BSS Transition Management");
if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
&wpa_s->scan_trigger_time)) {
wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
@@ -617,7 +907,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
}
/* Compare the Neighbor Report and scan results */
- bss = compare_scan_neighbor_results(wpa_s);
+ bss = compare_scan_neighbor_results(wpa_s, 0);
if (!bss) {
wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
@@ -625,24 +915,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
}
/* Associate to the network */
- /* Send the BSS Management Response - Accept */
- if (wpa_s->wnm_reply) {
- wpa_s->wnm_reply = 0;
- wnm_send_bss_transition_mgmt_resp(wpa_s,
- wpa_s->wnm_dialog_token,
- WNM_BSS_TM_ACCEPT,
- 0, bss->bssid);
- }
-
- if (bss == wpa_s->current_bss) {
- wpa_printf(MSG_DEBUG,
- "WNM: Already associated with the preferred candidate");
- return 1;
- }
-
- wpa_s->reassociate = 1;
- wpa_supplicant_connect(wpa_s, bss, ssid);
- wnm_deallocate_memory(wpa_s);
+ wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
return 1;
send_bss_resp_fail:
@@ -783,14 +1056,90 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
}
+static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ u8 i, found = 0;
+ size_t j;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Fetch current scan results from the driver for checking transition candidates");
+ scan_res = wpa_drv_get_scan_results2(wpa_s);
+ if (!scan_res) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results");
+ return 0;
+ }
+
+ if (scan_res->fetch_time.sec == 0)
+ os_get_reltime(&scan_res->fetch_time);
+
+ filter_scan_res(wpa_s, scan_res);
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (nei->preference_present && nei->preference == 0)
+ continue;
+
+ for (j = 0; j < scan_res->num; j++) {
+ struct wpa_scan_res *res;
+ const u8 *ssid_ie;
+
+ res = scan_res->res[j];
+ if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 ||
+ res->age > WNM_SCAN_RESULT_AGE * 1000)
+ continue;
+ bss = wpa_s->current_bss;
+ ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
+ if (bss && ssid_ie &&
+ (bss->ssid_len != ssid_ie[1] ||
+ os_memcmp(bss->ssid, ssid_ie + 2,
+ bss->ssid_len) != 0))
+ continue;
+
+ /* Potential candidate found */
+ found = 1;
+ scan_snr(res);
+ scan_est_throughput(wpa_s, res);
+ wpa_bss_update_scan_res(wpa_s, res,
+ &scan_res->fetch_time);
+ }
+ }
+
+ wpa_scan_results_free(scan_res);
+ if (!found) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: No transition candidate matches existing scan results");
+ return 0;
+ }
+
+ bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE);
+ if (!bss) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Comparison of scan results against transition candidates did not find matches");
+ return 0;
+ }
+
+ /* Associate to the network */
+ wnm_bss_tm_connect(wpa_s, bss, ssid, 0);
+ return 1;
+}
+
+
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
{
unsigned int beacon_int;
u8 valid_int;
+#ifdef CONFIG_MBO
+ const u8 *vendor;
+#endif /* CONFIG_MBO */
- if (pos + 5 > end)
+ if (end - pos < 5)
return;
if (wpa_s->current_bss)
@@ -810,10 +1159,23 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
wpa_s->wnm_dissoc_timer, valid_int);
+#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
+ if (wpa_s->reject_btm_req_reason) {
+ wpa_printf(MSG_INFO,
+ "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
+ wpa_s->reject_btm_req_reason);
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ wpa_s->reject_btm_req_reason,
+ 0, NULL);
+ return;
+ }
+#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
+
pos += 5;
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
- if (pos + 12 > end) {
+ if (end - pos < 12) {
wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
return;
}
@@ -824,7 +1186,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
char url[256];
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ if (end - pos < 1 || 1 + pos[0] > end - pos) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
"Management Request (URL)");
return;
@@ -849,6 +1211,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_MBO
+ vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
+ if (vendor)
+ wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
+#endif /* CONFIG_MBO */
+
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
unsigned int valid_ms;
@@ -860,7 +1228,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
if (wpa_s->wnm_neighbor_report_elements == NULL)
return;
- while (pos + 2 <= end &&
+ while (end - pos >= 2 &&
wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
{
u8 tag = *pos++;
@@ -868,7 +1236,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
tag);
- if (pos + len > end) {
+ if (len > end - pos) {
wpa_printf(MSG_DEBUG, "WNM: Truncated request");
return;
}
@@ -877,11 +1245,22 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
rep = &wpa_s->wnm_neighbor_report_elements[
wpa_s->wnm_num_neighbor_report];
wnm_parse_neighbor_report(wpa_s, pos, len, rep);
+ wpa_s->wnm_num_neighbor_report++;
}
pos += len;
- wpa_s->wnm_num_neighbor_report++;
}
+
+ if (!wpa_s->wnm_num_neighbor_report) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Candidate list included bit is set, but no candidates found");
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, wpa_s->wnm_dialog_token,
+ WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+ 0, NULL);
+ return;
+ }
+
wnm_sort_cand_list(wpa_s);
wnm_dump_cand_list(wpa_s);
valid_ms = valid_int * beacon_int * 128 / 125;
@@ -895,6 +1274,20 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_s->wnm_cand_valid_until.usec %= 1000000;
os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
+ /*
+ * Fetch the latest scan results from the kernel and check for
+ * candidates based on those results first. This can help in
+ * finding more up-to-date information should the driver has
+ * done some internal scanning operations after the last scan
+ * result update in wpa_supplicant.
+ */
+ if (wnm_fetch_scan_results(wpa_s) > 0)
+ return;
+
+ /*
+ * Try to use previously received scan results, if they are
+ * recent enough to use for a connection.
+ */
if (wpa_s->last_scan_res_used > 0) {
struct os_reltime now;
@@ -910,6 +1303,14 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
wnm_set_scan_freqs(wpa_s);
+ if (wpa_s->wnm_num_neighbor_report == 1) {
+ os_memcpy(wpa_s->next_scan_bssid,
+ wpa_s->wnm_neighbor_report_elements[0].bssid,
+ ETH_ALEN);
+ wpa_printf(MSG_DEBUG,
+ "WNM: Scan only for a specific BSSID since there is only a single candidate "
+ MACSTR, MAC2STR(wpa_s->next_scan_bssid));
+ }
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (reply) {
enum bss_trans_mgmt_status_code status;
@@ -927,16 +1328,17 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
- u8 query_reason)
+ u8 query_reason, int cand_list)
{
- u8 buf[1000], *pos;
+ u8 buf[2000], *pos;
struct ieee80211_mgmt *mgmt;
size_t len;
int ret;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
- MACSTR " query_reason=%u",
- MAC2STR(wpa_s->bssid), query_reason);
+ MACSTR " query_reason=%u%s",
+ MAC2STR(wpa_s->bssid), query_reason,
+ cand_list ? " candidate list" : "");
mgmt = (struct ieee80211_mgmt *) buf;
os_memset(&buf, 0, sizeof(buf));
@@ -951,6 +1353,9 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
pos = mgmt->u.action.u.bss_tm_query.variable;
+ if (cand_list)
+ pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
len = pos - (u8 *) &mgmt->u.action.category;
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -971,7 +1376,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
pos = data;
end = data + len;
- while (pos + 1 < end) {
+ while (end - pos > 1) {
ie = *pos++;
ie_len = *pos++;
wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
@@ -1009,7 +1414,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
url = NULL;
osu_method = 1;
} else {
- if (pos + url_len + 1 > ie_end) {
+ if (url_len + 1 > ie_end - pos) {
wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
url_len,
(int) (ie_end - pos));
@@ -1048,7 +1453,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
"Imminent - Reason Code %u "
"Re-Auth Delay %u URL Length %u",
code, reauth_delay, url_len);
- if (pos + url_len > ie_end)
+ if (url_len > ie_end - pos)
break;
url = os_malloc(url_len + 1);
if (url == NULL)
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 8de4348..81d8153 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -56,7 +56,7 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len);
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
- u8 query_reason);
+ u8 query_reason, int cand_list);
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 7ddae3d..a848b77 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,7 @@
#include <dirent.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
+#include "common/cli.h"
#include "common/wpa_ctrl.h"
#include "utils/common.h"
#include "utils/eloop.h"
@@ -28,43 +29,13 @@
static const char *const wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const wpa_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const wpa_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-" notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-" notice, this list of conditions and the following disclaimer in the\n"
-" documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-" names of its contributors may be used to endorse or promote products\n"
-" derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
+"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
+
+#define VENDOR_ELEM_FRAME_ID \
+ " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
+ "3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \
+ "7: GO Neg Resp, 8: GO Neg Conf, 9: Inv Req, 10: Inv Resp, " \
+ "11: Assoc Req (P2P), 12: Assoc Resp (P2P)"
static struct wpa_ctrl *ctrl_conn;
static struct wpa_ctrl *mon_conn;
@@ -84,11 +55,6 @@ static int ping_interval = 5;
static int interactive = 0;
static char *ifname_prefix = NULL;
-struct cli_txt_entry {
- struct dl_list list;
- char *txt;
-};
-
static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
@@ -124,168 +90,6 @@ static void usage(void)
}
-static void cli_txt_list_free(struct cli_txt_entry *e)
-{
- dl_list_del(&e->list);
- os_free(e->txt);
- os_free(e);
-}
-
-
-static void cli_txt_list_flush(struct dl_list *list)
-{
- struct cli_txt_entry *e;
- while ((e = dl_list_first(list, struct cli_txt_entry, list)))
- cli_txt_list_free(e);
-}
-
-
-static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
- const char *txt)
-{
- struct cli_txt_entry *e;
- dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
- if (os_strcmp(e->txt, txt) == 0)
- return e;
- }
- return NULL;
-}
-
-
-static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
-{
- struct cli_txt_entry *e;
- e = cli_txt_list_get(txt_list, txt);
- if (e)
- cli_txt_list_free(e);
-}
-
-
-static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
-{
- u8 addr[ETH_ALEN];
- char buf[18];
- if (hwaddr_aton(txt, addr) < 0)
- return;
- os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- cli_txt_list_del(txt_list, buf);
-}
-
-
-#ifdef CONFIG_P2P
-static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
- int separator)
-{
- const char *end;
- char *buf;
- end = os_strchr(txt, separator);
- if (end == NULL)
- end = txt + os_strlen(txt);
- buf = dup_binstr(txt, end - txt);
- if (buf == NULL)
- return;
- cli_txt_list_del(txt_list, buf);
- os_free(buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
-{
- struct cli_txt_entry *e;
- e = cli_txt_list_get(txt_list, txt);
- if (e)
- return 0;
- e = os_zalloc(sizeof(*e));
- if (e == NULL)
- return -1;
- e->txt = os_strdup(txt);
- if (e->txt == NULL) {
- os_free(e);
- return -1;
- }
- dl_list_add(txt_list, &e->list);
- return 0;
-}
-
-
-#ifdef CONFIG_P2P
-static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
-{
- u8 addr[ETH_ALEN];
- char buf[18];
- if (hwaddr_aton(txt, addr) < 0)
- return -1;
- os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- return cli_txt_list_add(txt_list, buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
- int separator)
-{
- const char *end;
- char *buf;
- int ret;
- end = os_strchr(txt, separator);
- if (end == NULL)
- end = txt + os_strlen(txt);
- buf = dup_binstr(txt, end - txt);
- if (buf == NULL)
- return -1;
- ret = cli_txt_list_add(txt_list, buf);
- os_free(buf);
- return ret;
-}
-
-
-static char ** cli_txt_list_array(struct dl_list *txt_list)
-{
- unsigned int i, count = dl_list_len(txt_list);
- char **res;
- struct cli_txt_entry *e;
-
- res = os_calloc(count + 1, sizeof(char *));
- if (res == NULL)
- return NULL;
-
- i = 0;
- dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
- res[i] = os_strdup(e->txt);
- if (res[i] == NULL)
- break;
- i++;
- }
-
- return res;
-}
-
-
-static int get_cmd_arg_num(const char *str, int pos)
-{
- int arg = 0, i;
-
- for (i = 0; i <= pos; i++) {
- if (str[i] != ' ') {
- arg++;
- while (i <= pos && str[i] != ' ')
- i++;
- }
- }
-
- if (arg > 0)
- arg--;
- return arg;
-}
-
-
-static int str_starts(const char *src, const char *match)
-{
- return os_strncmp(src, match, os_strlen(match)) == 0;
-}
-
-
static int wpa_cli_show_event(const char *event)
{
const char *start;
@@ -452,36 +256,6 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
}
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
- char *argv[])
-{
- int i, res;
- char *pos, *end;
-
- pos = buf;
- end = buf + buflen;
-
- res = os_snprintf(pos, end - pos, "%s", cmd);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
-
- for (i = 0; i < argc; i++) {
- res = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
- }
-
- buf[buflen - 1] = '\0';
- return 0;
-
-fail:
- printf("Too long command\n");
- return -1;
-}
-
-
static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
int argc, char *argv[])
{
@@ -581,7 +355,7 @@ static char ** wpa_cli_complete_help(const char *str, int pos)
static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
+ printf("%s\n\n%s\n", wpa_cli_version, cli_full_license);
return 0;
}
@@ -677,7 +451,10 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
- "reassoc_same_bss_optim", "wps_priority"
+ "reassoc_same_bss_optim", "wps_priority",
+#ifdef CONFIG_TESTING_OPTIONS
+ "ignore_auth_resp",
+#endif /* CONFIG_TESTING_OPTIONS */
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -705,6 +482,13 @@ static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
@@ -1548,7 +1332,7 @@ static const char *network_fields[] = {
"ssid", "scan_ssid", "bssid", "bssid_blacklist",
"bssid_whitelist", "psk", "proto", "key_mgmt",
"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
- "freq_list",
+ "freq_list", "max_oper_chwidth",
#ifdef IEEE8021X_EAPOL
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
@@ -1606,7 +1390,7 @@ static const char *network_fields[] = {
#ifdef CONFIG_HS20
"update_identifier",
#endif /* CONFIG_HS20 */
- "mac_addr"
+ "mac_addr", "pbss", "wps_disabled"
};
@@ -1764,6 +1548,13 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_abort_scan(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ABORT_SCAN");
+}
+
+
static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
@@ -1804,6 +1595,48 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
}
+static char ** wpa_cli_complete_get_capability(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "eap", "pairwise", "group", "group_mgmt", "key_mgmt",
+ "proto", "auth_alg", "modes", "channels", "freq",
+#ifdef CONFIG_TDLS
+ "tdls",
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_ERP
+ "erp",
+#endif /* CONFIG_ERP */
+#ifdef CONFIG_FIPS
+ "fips",
+#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+ "acs",
+#endif /* CONFIG_ACS */
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+ char **res = NULL;
+
+ if (arg == 1) {
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (res[i] == NULL)
+ return res;
+ }
+ }
+ if (arg == 2) {
+ res = os_calloc(1 + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ res[0] = os_strdup("strict");
+ }
+ return res;
+}
+
+
static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
printf("Available interfaces:\n");
@@ -1866,14 +1699,15 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
/*
* INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
- * <driver_param>TAB<bridge_name>[TAB<create>]
+ * <driver_param>TAB<bridge_name>[TAB<create>[TAB<type>]]
*/
res = os_snprintf(cmd, sizeof(cmd),
- "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s",
+ "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
argv[0],
argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
- argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "");
+ argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "",
+ argc > 7 ? argv[7] : "");
if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
@@ -1913,6 +1747,12 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
printf("Not connected to hostapd - command dropped.\n");
return -1;
}
+ if (ifname_prefix) {
+ os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+ ifname_prefix, cmd);
+ buf[sizeof(buf) - 1] = '\0';
+ cmd = buf;
+ }
len = sizeof(buf) - 1;
ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
@@ -2022,6 +1862,20 @@ static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
}
+
+static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv);
+}
+
#endif /* CONFIG_MESH */
@@ -2141,6 +1995,13 @@ static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2477,6 +2338,27 @@ static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
}
+
+static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR_ELEM_ADD", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_vendor_elem_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR_ELEM_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv);
+}
+
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
@@ -2719,6 +2601,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv);
+}
+
+
static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2823,6 +2712,20 @@ static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2880,6 +2783,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "get", wpa_cli_cmd_get, wpa_cli_complete_get,
cli_cmd_flag_none,
"<name> = get information" },
+ { "driver_flags", wpa_cli_cmd_driver_flags, NULL,
+ cli_cmd_flag_none,
+ "= list driver flags" },
{ "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
@@ -3001,11 +2907,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "scan_results", wpa_cli_cmd_scan_results, NULL,
cli_cmd_flag_none,
"= get latest scan results" },
+ { "abort_scan", wpa_cli_cmd_abort_scan, NULL,
+ cli_cmd_flag_none,
+ "= request ongoing scan to be aborted" },
{ "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
- { "get_capability", wpa_cli_cmd_get_capability, NULL,
- cli_cmd_flag_none,
+ { "get_capability", wpa_cli_cmd_get_capability,
+ wpa_cli_complete_get_capability, cli_cmd_flag_none,
"<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
"= get capabilities" },
{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
@@ -3017,8 +2926,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "interface_add", wpa_cli_cmd_interface_add, NULL,
cli_cmd_flag_none,
"<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
- " <bridge_name> = adds new interface, all parameters but <ifname>\n"
- " are optional" },
+ " <bridge_name> <create> <type> = adds new interface, all "
+ "parameters but\n"
+ " <ifname> are optional. Supported types are station ('sta') and "
+ "AP ('ap')" },
{ "interface_remove", wpa_cli_cmd_interface_remove, NULL,
cli_cmd_flag_none,
"<ifname> = removes the interface" },
@@ -3157,6 +3068,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
cli_cmd_flag_none,
"<ifname> = Remove mesh group interface" },
+ { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL,
+ cli_cmd_flag_none,
+ "<addr> = Remove a mesh peer" },
+ { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
+ cli_cmd_flag_none,
+ "<addr> [duration=<seconds>] = Add a mesh peer" },
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
@@ -3180,6 +3097,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
"<ifname> = remove P2P group interface (terminate group if GO)" },
{ "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
"[ht40] = add a new P2P group (local end as GO)" },
+ { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL,
+ cli_cmd_flag_none,
+ "<dev_addr> = Get peer interface address on local GO using peer Device Address" },
{ "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
@@ -3248,6 +3168,18 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<address|iface=address> = remove a peer from all groups" },
+ { "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL,
+ cli_cmd_flag_none,
+ "<frame id> <hexdump of elem(s)> = add vendor specific IEs to frame(s)\n"
+ VENDOR_ELEM_FRAME_ID },
+ { "vendor_elem_get", wpa_cli_cmd_vendor_elem_get, NULL,
+ cli_cmd_flag_none,
+ "<frame id> = get vendor specific IE(s) to frame(s)\n"
+ VENDOR_ELEM_FRAME_ID },
+ { "vendor_elem_remove", wpa_cli_cmd_vendor_elem_remove, NULL,
+ cli_cmd_flag_none,
+ "<frame id> <hexdump of elem(s)> = remove vendor specific IE(s) in frame(s)\n"
+ VENDOR_ELEM_FRAME_ID },
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
@@ -3336,6 +3268,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
+ { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL,
+ cli_cmd_flag_none,
+ "= set signal monitor parameters" },
{ "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
cli_cmd_flag_none,
"= get TX/RX packet counters" },
@@ -3350,7 +3285,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
"<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
{ "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
- "<query reason> = Send BSS Transition Management Query" },
+ "<query reason> [list] = Send BSS Transition Management Query" },
#endif /* CONFIG_WNM */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
@@ -3367,8 +3302,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
},
{ "neighbor_rep_request",
wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
- "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
- "(with optional given SSID, default: current SSID)"
+ "[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)"
},
{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
"= flush ERP keys" },
@@ -3380,6 +3314,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
cli_cmd_flag_none,
"<interface type> = retrieve preferred freq list for the specified interface type" },
+ { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL,
+ cli_cmd_flag_none,
+ "<freq> <period> <interval> <count> = start P2P listen offload" },
+ { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL,
+ cli_cmd_flag_none,
+ "= stop P2P listen offload" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3578,12 +3518,6 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int str_match(const char *a, const char *b)
-{
- return os_strncmp(a, b, os_strlen(b)) == 0;
-}
-
-
static int wpa_cli_exec(const char *program, const char *arg1,
const char *arg2)
{
@@ -3591,6 +3525,10 @@ static int wpa_cli_exec(const char *program, const char *arg1,
size_t len;
int res;
+ /* If no interface is specified, set the global */
+ if (!arg1)
+ arg1 = "global";
+
len = os_strlen(arg1) + os_strlen(arg2) + 2;
arg = os_malloc(len);
if (arg == NULL)
@@ -3635,7 +3573,7 @@ static void wpa_cli_action_process(const char *msg)
pos = prev;
}
- if (str_match(pos, WPA_EVENT_CONNECTED)) {
+ if (str_starts(pos, WPA_EVENT_CONNECTED)) {
int new_id = -1;
os_unsetenv("WPA_ID");
os_unsetenv("WPA_ID_STR");
@@ -3671,44 +3609,48 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_last_id = new_id;
wpa_cli_exec(action_file, ifname, "CONNECTED");
}
- } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+ } else if (str_starts(pos, WPA_EVENT_DISCONNECTED)) {
if (wpa_cli_connected) {
wpa_cli_connected = 0;
wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
- } else if (str_match(pos, MESH_GROUP_STARTED)) {
+ } else if (str_starts(pos, AP_EVENT_ENABLED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_starts(pos, AP_EVENT_DISABLED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_starts(pos, MESH_GROUP_STARTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_GROUP_REMOVED)) {
+ } else if (str_starts(pos, MESH_GROUP_REMOVED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_PEER_CONNECTED)) {
+ } else if (str_starts(pos, MESH_PEER_CONNECTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+ } else if (str_starts(pos, MESH_PEER_DISCONNECTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+ } else if (str_starts(pos, P2P_EVENT_GROUP_STARTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+ } else if (str_starts(pos, P2P_EVENT_GROUP_REMOVED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+ } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+ } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+ } else if (str_starts(pos, P2P_EVENT_GO_NEG_FAILURE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+ } else if (str_starts(pos, WPS_EVENT_SUCCESS)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPS_EVENT_FAIL)) {
+ } else if (str_starts(pos, WPS_EVENT_FAIL)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, AP_STA_CONNECTED)) {
+ } else if (str_starts(pos, AP_STA_CONNECTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+ } else if (str_starts(pos, AP_STA_DISCONNECTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+ } else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+ } else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
+ } else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
+ } else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
}
@@ -3818,7 +3760,7 @@ static int check_terminating(const char *msg)
pos = msg;
}
- if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+ if (str_starts(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
edit_clear_line();
printf("\rConnection to wpa_supplicant lost - trying to "
"reconnect\n");
@@ -3869,37 +3811,6 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
}
}
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
-{
- char *pos;
- int argc = 0;
-
- pos = cmd;
- for (;;) {
- while (*pos == ' ')
- pos++;
- if (*pos == '\0')
- break;
- argv[argc] = pos;
- argc++;
- if (argc == max_args)
- break;
- if (*pos == '"') {
- char *pos2 = os_strrchr(pos, '"');
- if (pos2)
- pos = pos2 + 1;
- }
- while (*pos != '\0' && *pos != ' ')
- pos++;
- if (*pos == ' ')
- *pos++ = '\0';
- }
-
- return argc;
-}
-
static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
{
@@ -4084,7 +3995,7 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
- if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+ if (wpa_cli_open_connection(ctrl_ifname, 1)) {
if (!warning_displayed) {
printf("Could not connect to wpa_supplicant: "
"%s - re-trying\n",
@@ -4309,7 +4220,7 @@ int main(int argc, char *argv[])
interactive = (argc == optind) && (action_file == NULL);
if (interactive)
- printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
+ printf("%s\n\n%s\n\n", wpa_cli_version, cli_license);
if (eloop_init())
return -1;
@@ -4373,7 +4284,7 @@ int main(int argc, char *argv[])
}
}
- if (daemonize && os_daemonize(pid_file))
+ if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
if (action_file)
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 850ec40..511df4f 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -29,6 +29,8 @@ struct wpa_priv_interface {
char *sock_name;
int fd;
+ void *ctx;
+
const struct wpa_driver_ops *driver;
void *drv_priv;
void *drv_global_priv;
@@ -40,6 +42,10 @@ struct wpa_priv_interface {
struct sockaddr_un l2_addr;
};
+struct wpa_priv_global {
+ struct wpa_priv_interface *interfaces;
+};
+
static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
struct sockaddr_un *from)
@@ -65,7 +71,8 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
if (iface->driver->init2) {
if (iface->driver->global_init) {
- iface->drv_global_priv = iface->driver->global_init();
+ iface->drv_global_priv =
+ iface->driver->global_init(iface->ctx);
if (!iface->drv_global_priv) {
wpa_printf(MSG_INFO,
"Failed to initialize driver global context");
@@ -638,7 +645,7 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
+wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
{
struct wpa_priv_interface *iface;
char *pos;
@@ -654,6 +661,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
if (iface == NULL)
return NULL;
iface->fd = -1;
+ iface->ctx = ctx;
len = pos - params;
iface->driver_name = dup_binstr(params, len);
@@ -1002,6 +1010,37 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct wpa_priv_global *global = ctx;
+ struct wpa_priv_interface *iface;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ for (iface = global->interfaces; iface; iface = iface->next) {
+ if (os_strcmp(iface->ifname, data->interface_status.ifname) ==
+ 0)
+ break;
+ }
+ if (iface && iface->driver->get_ifindex) {
+ unsigned int ifindex;
+
+ ifindex = iface->driver->get_ifindex(iface->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_printf(MSG_DEBUG,
+ "%s: interface status ifindex %d mismatch (%d)",
+ iface->ifname, ifindex,
+ data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (iface)
+ wpa_supplicant_event(iface, event, data);
+}
+
+
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1060,7 +1099,7 @@ static void wpa_priv_fd_workaround(void)
static void usage(void)
{
printf("wpa_priv v" VERSION_STR "\n"
- "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and "
+ "Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> and "
"contributors\n"
"\n"
"usage:\n"
@@ -1077,13 +1116,17 @@ int main(int argc, char *argv[])
char *pid_file = NULL;
int daemonize = 0;
char *ctrl_dir = "/var/run/wpa_priv";
- struct wpa_priv_interface *interfaces = NULL, *iface;
+ struct wpa_priv_global global;
+ struct wpa_priv_interface *iface;
if (os_program_init())
return -1;
wpa_priv_fd_workaround();
+ os_memset(&global, 0, sizeof(global));
+ global.interfaces = NULL;
+
for (;;) {
c = getopt(argc, argv, "Bc:dP:");
if (c < 0)
@@ -1121,14 +1164,14 @@ int main(int argc, char *argv[])
for (i = optind; i < argc; i++) {
wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
- iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
+ iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
if (iface == NULL)
goto out;
- iface->next = interfaces;
- interfaces = iface;
+ iface->next = global.interfaces;
+ global.interfaces = iface;
}
- if (daemonize && os_daemonize(pid_file))
+ if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
goto out;
eloop_register_signal_terminate(wpa_priv_terminate, NULL);
@@ -1137,7 +1180,7 @@ int main(int argc, char *argv[])
ret = 0;
out:
- iface = interfaces;
+ iface = global.interfaces;
while (iface) {
struct wpa_priv_interface *prev = iface;
iface = iface->next;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ef55fdc..7361ee9 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,10 @@
*/
#include "includes.h"
+#ifdef CONFIG_MATCH_IFACE
+#include <net/if.h>
+#include <fnmatch.h>
+#endif /* CONFIG_MATCH_IFACE */
#include "common.h"
#include "crypto/random.h"
@@ -58,7 +62,7 @@
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
const char *const wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -188,7 +192,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
const u8 *bssid = wpa_s->bssid;
- if (is_zero_ether_addr(bssid))
+ if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
@@ -397,6 +403,18 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
}
+static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss_tmp_disallowed *bss, *prev;
+
+ dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ dl_list_del(&bss->list);
+ os_free(bss);
+ }
+}
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -536,6 +554,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->last_scan_res = NULL;
#ifdef CONFIG_HS20
+ if (wpa_s->drv_priv)
+ wpa_drv_configure_frame_filters(wpa_s, 0);
hs20_deinit(wpa_s);
#endif /* CONFIG_HS20 */
@@ -545,6 +565,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
}
wmm_ac_notify_disassoc(wpa_s);
+
+ wpa_s->sched_scan_plans_num = 0;
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = NULL;
+
+#ifdef CONFIG_MBO
+ wpa_s->non_pref_chan_num = 0;
+ os_free(wpa_s->non_pref_chan);
+ wpa_s->non_pref_chan = NULL;
+#endif /* CONFIG_MBO */
+
+ free_bss_tmp_disallowed(wpa_s);
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
}
@@ -963,6 +998,11 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
wpa_supplicant_terminate_proc(global);
}
}
+
+ if (wpa_debug_reopen_file() < 0) {
+ /* Ignore errors since we cannot really do much to fix this */
+ wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
+ }
}
@@ -1150,6 +1190,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
+#ifdef CONFIG_NO_WPA
+ wpa_s->group_cipher = WPA_CIPHER_NONE;
+ wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+#else /* CONFIG_NO_WPA */
sel = ie.group_cipher & ssid->group_cipher;
wpa_s->group_cipher = wpa_pick_group_cipher(sel);
if (wpa_s->group_cipher < 0) {
@@ -1169,6 +1213,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
wpa_cipher_txt(wpa_s->pairwise_cipher));
+#endif /* CONFIG_NO_WPA */
sel = ie.key_mgmt & ssid->key_mgmt;
#ifdef CONFIG_SAE
@@ -1279,7 +1324,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
int psk_set = 0;
if (ssid->psk_set) {
- wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
+ NULL);
psk_set = 1;
}
#ifndef CONFIG_NO_PBKDF2
@@ -1290,7 +1336,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
psk_set = 1;
os_memset(psk, 0, sizeof(psk));
}
@@ -1328,7 +1374,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
"external passphrase)",
psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+ NULL);
psk_set = 1;
os_memset(psk, 0, sizeof(psk));
} else
@@ -1341,7 +1388,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ext_password_free(pw);
return -1;
}
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+ NULL);
psk_set = 1;
os_memset(psk, 0, sizeof(psk));
} else {
@@ -1404,9 +1452,20 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
if (wpa_s->conf->hs20)
*pos |= 0x40; /* Bit 46 - WNM-Notification */
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
break;
case 6: /* Bits 48-55 */
break;
+ case 7: /* Bits 56-63 */
+ break;
+ case 8: /* Bits 64-71 */
+ if (wpa_s->conf->ftm_responder)
+ *pos |= 0x40; /* Bit 70 - FTM responder */
+ if (wpa_s->conf->ftm_initiator)
+ *pos |= 0x80; /* Bit 71 - FTM initiator */
+ break;
}
}
@@ -1416,6 +1475,9 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
u8 *pos = buf;
u8 len = 6, i;
+ if (len < 9 &&
+ (wpa_s->conf->ftm_initiator || wpa_s->conf->ftm_responder))
+ len = 9;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
if (buflen < (size_t) len + 2) {
@@ -1586,6 +1648,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_connect_work *cwork;
int rand_style;
+ wpa_s->own_disconnect_req = 0;
+
+ /*
+ * If we are starting a new connection, any previously pending EAPOL
+ * RX cannot be valid anymore.
+ */
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = NULL;
+
if (ssid->mac_addr == -1)
rand_style = wpa_s->conf->mac_addr;
else
@@ -1593,9 +1664,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
+ wpa_s->reassoc_same_ess = 0;
if (wpa_s->last_ssid == ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+ wpa_s->reassoc_same_ess = 1;
if (wpa_s->current_bss && wpa_s->current_bss == bss) {
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
@@ -1661,10 +1734,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
wpa_s->current_bss = bss;
- wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
- "ssid=\"%s\" id=%d",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->id);
+ wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->id);
#else /* CONFIG_MESH */
wpa_msg(wpa_s, MSG_ERROR,
"mesh mode support not included in the build");
@@ -1694,6 +1766,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
+ wpas_abort_ongoing_scan(wpa_s);
+
cwork = os_zalloc(sizeof(*cwork));
if (cwork == NULL)
return;
@@ -1715,6 +1789,36 @@ static int bss_is_ibss(struct wpa_bss *bss)
}
+static int drv_supports_vht(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 channel;
+ int i;
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht)
+ return 0;
+#endif /* CONFIG_HT_OVERRIDES */
+
+ hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ return 0;
+ for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ if (!mode)
+ return 0;
+
+ return mode->vht_capab != 0;
+}
+
+
void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -1727,8 +1831,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
u8 channel;
int i, chan_idx, ht40 = -1, res, obss_scan = 1;
- unsigned int j;
+ unsigned int j, k;
struct hostapd_freq_params vht_freq;
+ int chwidth, seg0, seg1;
+ u32 vht_caps = 0;
freq->freq = ssid->frequency;
@@ -1780,6 +1886,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!mode)
return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ freq->ht_enabled = 0;
+ return;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
freq->ht_enabled = ht_supported(mode);
if (!freq->ht_enabled)
return;
@@ -1801,6 +1914,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40)
+ return;
+#endif /* CONFIG_HT_OVERRIDES */
+
/* Check/setup HT40+/HT40- */
for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
if (ht40plus[j] == channel) {
@@ -1825,22 +1943,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
freq->channel = pri_chan->chan;
- switch (ht40) {
- case -1:
+ if (ht40 == -1) {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
return;
- freq->sec_channel_offset = -1;
- break;
- case 1:
+ } else {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
return;
- freq->sec_channel_offset = 1;
- break;
- default:
- break;
}
+ freq->sec_channel_offset = ht40;
- if (freq->sec_channel_offset && obss_scan) {
+ if (obss_scan) {
struct wpa_scan_results *scan_res;
scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -1878,12 +1990,12 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
"IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
freq->channel, freq->sec_channel_offset);
- /* Not sure if mesh is ready for VHT */
- if (ssid->mode != WPAS_MODE_IBSS)
+ if (!drv_supports_vht(wpa_s, ssid))
return;
/* For IBSS check VHT_IBSS flag */
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
return;
vht_freq = *freq;
@@ -1914,12 +2026,55 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
return;
}
+ chwidth = VHT_CHANWIDTH_80MHZ;
+ seg0 = vht80[j] + 6;
+ seg1 = 0;
+
+ if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) {
+ /* setup center_freq2, bandwidth */
+ for (k = 0; k < ARRAY_SIZE(vht80); k++) {
+ /* Only accept 80 MHz segments separated by a gap */
+ if (j == k || abs(vht80[j] - vht80[k]) == 16)
+ continue;
+ for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
+ struct hostapd_channel_data *chan;
+
+ chan = hw_get_channel_chan(mode, i, NULL);
+ if (!chan)
+ continue;
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+
+ /* Found a suitable second segment for 80+80 */
+ chwidth = VHT_CHANWIDTH_80P80MHZ;
+ vht_caps |=
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ seg1 = vht80[k] + 6;
+ }
+
+ if (chwidth == VHT_CHANWIDTH_80P80MHZ)
+ break;
+ }
+ } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+ if (freq->freq == 5180) {
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ seg0 = 50;
+ } else if (freq->freq == 5520) {
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ seg0 = 114;
+ }
+ }
+
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
freq->channel, freq->ht_enabled,
vht_freq.vht_enabled,
freq->sec_channel_offset,
- VHT_CHANWIDTH_80MHZ,
- vht80[j] + 6, 0, 0) != 0)
+ chwidth, seg0, seg1, vht_caps) != 0)
return;
*freq = vht_freq;
@@ -1944,6 +2099,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
int wep_keys_set = 0;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
+ u8 prev_bssid[ETH_ALEN];
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -1952,6 +2108,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct ieee80211_vht_capabilities vhtcaps;
struct ieee80211_vht_capabilities vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_MBO
+ const u8 *mbo = NULL;
+#endif /* CONFIG_MBO */
if (deinit) {
if (work->started) {
@@ -1974,6 +2133,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
os_memset(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
wpa_s->eap_expected_failure = 0;
@@ -2015,7 +2175,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
} else {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+ if (bss)
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ else
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
}
if (!wpa_s->pno)
wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -2136,25 +2299,21 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
#endif /* CONFIG_P2P */
-#ifdef CONFIG_HS20
- if (is_hs20_network(wpa_s, ssid, bss)) {
- struct wpabuf *hs20;
- hs20 = wpabuf_alloc(20);
- if (hs20) {
- int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
- size_t len;
-
- wpas_hs20_add_indication(hs20, pps_mo_id);
- len = sizeof(wpa_ie) - wpa_ie_len;
- if (wpabuf_len(hs20) <= len) {
- os_memcpy(wpa_ie + wpa_ie_len,
- wpabuf_head(hs20), wpabuf_len(hs20));
- wpa_ie_len += wpabuf_len(hs20);
- }
- wpabuf_free(hs20);
+#ifdef CONFIG_MBO
+ if (bss) {
+ mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (mbo) {
+ int len;
+
+ len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
+ wpa_ie + wpa_ie_len,
+ sizeof(wpa_ie) -
+ wpa_ie_len);
+ if (len > 0)
+ wpa_ie_len += len;
}
}
-#endif /* CONFIG_HS20 */
+#endif /* CONFIG_MBO */
/*
* Workaround: Add Extended Capabilities element only if the AP
@@ -2164,6 +2323,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
* element in all cases, it is justifiable to skip it to avoid
* interoperability issues.
*/
+ if (ssid->p2p_group)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
u8 ext_capab[18];
int ext_capab_len;
@@ -2180,6 +2344,29 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
}
+#ifdef CONFIG_HS20
+ if (is_hs20_network(wpa_s, ssid, bss)) {
+ struct wpabuf *hs20;
+
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+ size_t len;
+
+ wpas_hs20_add_indication(hs20, pps_mo_id);
+ len = sizeof(wpa_ie) - wpa_ie_len;
+ if (wpabuf_len(hs20) <= len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(hs20), wpabuf_len(hs20));
+ wpa_ie_len += wpabuf_len(hs20);
+ }
+ wpabuf_free(hs20);
+
+ hs20_configure_frame_filters(wpa_s);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
size_t len;
@@ -2204,6 +2391,17 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
#endif /* CONFIG_FST */
+#ifdef CONFIG_MBO
+ if (mbo) {
+ int len;
+
+ len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
+ sizeof(wpa_ie) - wpa_ie_len);
+ if (len >= 0)
+ wpa_ie_len += len;
+ }
+#endif /* CONFIG_MBO */
+
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
@@ -2256,9 +2454,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
params.bssid_hint = bss->bssid;
params.freq_hint = bss->freq;
+ params.pbss = bss_is_pbss(bss);
} else {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
+ params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
}
if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
@@ -2342,8 +2542,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.p2p = ssid->p2p_group;
- if (wpa_s->parent->set_sta_uapsd)
- params.uapsd = wpa_s->parent->sta_uapsd;
+ if (wpa_s->p2pdev->set_sta_uapsd)
+ params.uapsd = wpa_s->p2pdev->sta_uapsd;
else
params.uapsd = -1;
@@ -2384,6 +2584,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
#endif /* CONFIG_P2P */
+ if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
+ wpa_s->current_ssid)
+ params.prev_bssid = prev_bssid;
+
ret = wpa_drv_associate(wpa_s, &params);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -2451,8 +2655,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
- if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
wpa_s->current_bss = bss;
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+ }
+
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
@@ -2497,12 +2707,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
- if (!is_zero_ether_addr(wpa_s->bssid))
- addr = wpa_s->bssid;
- else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
- (wpa_s->wpa_state == WPA_AUTHENTICATING ||
- wpa_s->wpa_state == WPA_ASSOCIATING))
+ if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
addr = wpa_s->pending_bssid;
+ else if (!is_zero_ether_addr(wpa_s->bssid))
+ addr = wpa_s->bssid;
else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
/*
* When using driver-based BSS selection, we may not know the
@@ -2520,8 +2730,8 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
- wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
- wpa_s->ifname);
+ wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
+ wpa_s->ifname);
wpa_supplicant_leave_mesh(wpa_s);
}
#endif /* CONFIG_MESH */
@@ -2559,6 +2769,95 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
/**
+ * wpa_supplicant_add_network - Add a new network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (!ssid)
+ return NULL;
+ wpas_notify_network_added(wpa_s, ssid);
+ ssid->disabled = 1;
+ wpa_config_set_network_defaults(ssid);
+
+ return ssid;
+}
+
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+ struct wpa_ssid *ssid;
+ int was_disabled;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (!ssid)
+ return -1;
+ wpas_notify_network_removed(wpa_s, ssid);
+
+ if (wpa_s->last_ssid == ssid)
+ wpa_s->last_ssid = NULL;
+
+ if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ /*
+ * Invalidate the EAP session cache if the current or
+ * previously used network is removed.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ was_disabled = ssid->disabled;
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0)
+ return -2;
+
+ if (!was_disabled && wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG,
+ "Stop ongoing sched_scan to remove network from filters");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
* @wpa_s: wpa_supplicant structure for a network interface
* @ssid: wpa_ssid structure for a configured network or %NULL
@@ -2688,7 +2987,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
}
- if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+ if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
/* We are already associated with the selected network */
wpa_printf(MSG_DEBUG, "Already associated with the "
"selected network - do nothing");
@@ -2717,6 +3017,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
wpa_s->scan_req = NORMAL_SCAN_REQ;
+ wpas_scan_reset_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
}
@@ -2994,7 +3295,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i)
struct wpa_global *global = wpa_s->global;
if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
- global->drv_priv[i] = wpa_drivers[i]->global_init();
+ global->drv_priv[i] = wpa_drivers[i]->global_init(global);
if (global->drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize driver "
"'%s'", wpa_drivers[i]->name);
@@ -3077,6 +3378,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_PEERKEY
if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
wpa_s->current_ssid->peerkey &&
@@ -3361,8 +3669,11 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
wpa_s->parent = parent ? parent : wpa_s;
+ wpa_s->p2pdev = wpa_s->parent;
wpa_s->sched_scanning = 0;
+ dl_list_init(&wpa_s->bss_tmp_disallowed);
+
return wpa_s;
}
@@ -3614,8 +3925,8 @@ void wpa_supplicant_apply_vht_overrides(
if (!vhtcaps || !vhtcaps_mask)
return;
- vhtcaps->vht_capabilities_info = ssid->vht_capa;
- vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+ vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
+ vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
#ifdef CONFIG_HT_OVERRIDES
/* if max ampdu is <= 3, we have to make the HT cap the same */
@@ -3637,15 +3948,17 @@ void wpa_supplicant_apply_vht_overrides(
#define OVERRIDE_MCS(i) \
if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
- 3 << 2 * (i - 1); \
+ host_to_le16(3 << 2 * (i - 1)); \
vhtcaps->vht_supported_mcs_set.tx_map |= \
- ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \
+ host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \
+ 2 * (i - 1)); \
} \
if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
- 3 << 2 * (i - 1); \
+ host_to_le16(3 << 2 * (i - 1)); \
vhtcaps->vht_supported_mcs_set.rx_map |= \
- ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \
+ host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \
+ 2 * (i - 1)); \
}
OVERRIDE_MCS(1);
@@ -3817,8 +4130,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
}
-const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+static const u8 * wpas_fst_get_peer_first(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -3830,8 +4144,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
}
-const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+static const u8 * wpas_fst_get_peer_next(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
{
return NULL;
}
@@ -3870,6 +4185,55 @@ static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
}
+enum wpa_radio_work_band wpas_freq_to_band(int freq)
+{
+ if (freq < 3000)
+ return BAND_2_4_GHZ;
+ if (freq > 50000)
+ return BAND_60_GHZ;
+ return BAND_5_GHZ;
+}
+
+
+unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
+{
+ int i;
+ unsigned int band = 0;
+
+ if (freqs) {
+ /* freqs are specified for the radio work */
+ for (i = 0; freqs[i]; i++)
+ band |= wpas_freq_to_band(freqs[i]);
+ } else {
+ /*
+ * freqs are not specified, implies all
+ * the supported freqs by HW
+ */
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].num_channels != 0) {
+ if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211B ||
+ wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211G)
+ band |= BAND_2_4_GHZ;
+ else if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211A)
+ band |= BAND_5_GHZ;
+ else if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211AD)
+ band |= BAND_60_GHZ;
+ else if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211ANY)
+ band = BAND_2_4_GHZ | BAND_5_GHZ |
+ BAND_60_GHZ;
+ }
+ }
+ }
+
+ return band;
+}
+
+
static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
const char *rn)
{
@@ -3922,11 +4286,103 @@ static void radio_work_free(struct wpa_radio_work *work)
}
#endif /* CONFIG_P2P */
+ if (work->started) {
+ work->wpa_s->radio->num_active_works--;
+ wpa_dbg(work->wpa_s, MSG_DEBUG,
+ "radio_work_free('%s'@%p: num_active_works --> %u",
+ work->type, work,
+ work->wpa_s->radio->num_active_works);
+ }
+
dl_list_del(&work->list);
os_free(work);
}
+static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
+{
+ struct wpa_radio_work *active_work = NULL;
+ struct wpa_radio_work *tmp;
+
+ /* Get the active work to know the type and band. */
+ dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
+ if (tmp->started) {
+ active_work = tmp;
+ break;
+ }
+ }
+
+ if (!active_work) {
+ /* No active work, start one */
+ radio->num_active_works = 0;
+ dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
+ list) {
+ if (os_strcmp(tmp->type, "scan") == 0 &&
+ radio->external_scan_running &&
+ (((struct wpa_driver_scan_params *)
+ tmp->ctx)->only_new_results ||
+ tmp->wpa_s->clear_driver_scan_cache))
+ continue;
+ return tmp;
+ }
+ return NULL;
+ }
+
+ if (os_strcmp(active_work->type, "sme-connect") == 0 ||
+ os_strcmp(active_work->type, "connect") == 0) {
+ /*
+ * If the active work is either connect or sme-connect,
+ * do not parallelize them with other radio works.
+ */
+ wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+ "Do not parallelize radio work with %s",
+ active_work->type);
+ return NULL;
+ }
+
+ dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
+ if (tmp->started)
+ continue;
+
+ /*
+ * If connect or sme-connect are enqueued, parallelize only
+ * those operations ahead of them in the queue.
+ */
+ if (os_strcmp(tmp->type, "connect") == 0 ||
+ os_strcmp(tmp->type, "sme-connect") == 0)
+ break;
+
+ /*
+ * Check that the radio works are distinct and
+ * on different bands.
+ */
+ if (os_strcmp(active_work->type, tmp->type) != 0 &&
+ (active_work->bands != tmp->bands)) {
+ /*
+ * If a scan has to be scheduled through nl80211 scan
+ * interface and if an external scan is already running,
+ * do not schedule the scan since it is likely to get
+ * rejected by kernel.
+ */
+ if (os_strcmp(tmp->type, "scan") == 0 &&
+ radio->external_scan_running &&
+ (((struct wpa_driver_scan_params *)
+ tmp->ctx)->only_new_results ||
+ tmp->wpa_s->clear_driver_scan_cache))
+ continue;
+
+ wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+ "active_work:%s new_work:%s",
+ active_work->type, tmp->type);
+ return tmp;
+ }
+ }
+
+ /* Did not find a radio work to schedule in parallel. */
+ return NULL;
+}
+
+
static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_radio *radio = eloop_ctx;
@@ -3935,26 +4391,48 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
struct wpa_supplicant *wpa_s;
work = dl_list_first(&radio->work, struct wpa_radio_work, list);
- if (work == NULL)
+ if (work == NULL) {
+ radio->num_active_works = 0;
return;
-
- if (work->started)
- return; /* already started and still in progress */
+ }
wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
radio_list);
- if (wpa_s && wpa_s->radio->external_scan_running) {
- wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
- return;
+
+ if (!(wpa_s &&
+ wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
+ if (work->started)
+ return; /* already started and still in progress */
+
+ if (wpa_s && wpa_s->radio->external_scan_running) {
+ wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
+ return;
+ }
+ } else {
+ work = NULL;
+ if (radio->num_active_works < MAX_ACTIVE_WORKS) {
+ /* get the work to schedule next */
+ work = radio_work_get_next_work(radio);
+ }
+ if (!work)
+ return;
}
+ wpa_s = work->wpa_s;
os_get_reltime(&now);
os_reltime_sub(&now, &work->time, &diff);
- wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait",
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Starting radio work '%s'@%p after %ld.%06ld second wait",
work->type, work, diff.sec, diff.usec);
work->started = 1;
work->time = now;
+ radio->num_active_works++;
+
work->cb(work, 0);
+
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
+ radio->num_active_works < MAX_ACTIVE_WORKS)
+ radio_work_check_next(wpa_s);
}
@@ -4062,6 +4540,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
void (*cb)(struct wpa_radio_work *work, int deinit),
void *ctx)
{
+ struct wpa_radio *radio = wpa_s->radio;
struct wpa_radio_work *work;
int was_empty;
@@ -4076,6 +4555,16 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
work->cb = cb;
work->ctx = ctx;
+ if (freq)
+ work->bands = wpas_freq_to_band(freq);
+ else if (os_strcmp(type, "scan") == 0 ||
+ os_strcmp(type, "p2p-scan") == 0)
+ work->bands = wpas_get_bands(wpa_s,
+ ((struct wpa_driver_scan_params *)
+ ctx)->freqs);
+ else
+ work->bands = wpas_get_bands(wpa_s, NULL);
+
was_empty = dl_list_empty(&wpa_s->radio->work);
if (next)
dl_list_add(&wpa_s->radio->work, &work->list);
@@ -4084,6 +4573,12 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
if (was_empty) {
wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
radio_work_check_next(wpa_s);
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
+ && radio->num_active_works < MAX_ACTIVE_WORKS) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Try to schedule a radio work (num_active_works=%u)",
+ radio->num_active_works);
+ radio_work_check_next(wpa_s);
}
return 0;
@@ -4339,6 +4834,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+ wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
+ wpa_s->max_sched_scan_plan_interval =
+ capa.max_sched_scan_plan_interval;
+ wpa_s->max_sched_scan_plan_iterations =
+ capa.max_sched_scan_plan_iterations;
wpa_s->sched_scan_supported = capa.sched_scan_supported;
wpa_s->max_match_sets = capa.max_match_sets;
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
@@ -4478,6 +4978,17 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpas_rrm_reset(wpa_s);
+ wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
+
+#ifdef CONFIG_HS20
+ hs20_init(wpa_s);
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
+#endif /* CONFIG_MBO */
+
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
return 0;
}
@@ -4493,6 +5004,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
iface = global->ifaces;
while (iface) {
+ if (iface->p2pdev == wpa_s)
+ iface->p2pdev = iface->parent;
if (iface == wpa_s || iface->parent != wpa_s) {
iface = iface->next;
continue;
@@ -4563,6 +5076,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_MATCH_IFACE
+
+/**
+ * wpa_supplicant_match_iface - Match an interface description to a name
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Name of the interface to match
+ * Returns: Pointer to the created interface description or %NULL on failure
+ */
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+ const char *ifname)
+{
+ int i;
+ struct wpa_interface *iface, *miface;
+
+ for (i = 0; i < global->params.match_iface_count; i++) {
+ miface = &global->params.match_ifaces[i];
+ if (!miface->ifname ||
+ fnmatch(miface->ifname, ifname, 0) == 0) {
+ iface = os_zalloc(sizeof(*iface));
+ if (!iface)
+ return NULL;
+ *iface = *miface;
+ iface->ifname = ifname;
+ return iface;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_supplicant_match_existing - Match existing interfaces
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_match_existing(struct wpa_global *global)
+{
+ struct if_nameindex *ifi, *ifp;
+ struct wpa_supplicant *wpa_s;
+ struct wpa_interface *iface;
+
+ ifp = if_nameindex();
+ if (!ifp) {
+ wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
+ return -1;
+ }
+
+ for (ifi = ifp; ifi->if_name; ifi++) {
+ wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
+ if (wpa_s)
+ continue;
+ iface = wpa_supplicant_match_iface(global, ifi->if_name);
+ if (iface) {
+ wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+ os_free(iface);
+ if (wpa_s)
+ wpa_s->matched = 1;
+ }
+ }
+
+ if_freenameindex(ifp);
+ return 0;
+}
+
+#endif /* CONFIG_MATCH_IFACE */
+
+
/**
* wpa_supplicant_add_iface - Add a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
@@ -4864,6 +5445,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->override_ctrl_interface)
global->params.override_ctrl_interface =
os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+ global->params.match_iface_count = params->match_iface_count;
+ if (params->match_iface_count) {
+ global->params.match_ifaces =
+ os_calloc(params->match_iface_count,
+ sizeof(struct wpa_interface));
+ os_memcpy(global->params.match_ifaces,
+ params->match_ifaces,
+ params->match_iface_count *
+ sizeof(struct wpa_interface));
+ }
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
if (params->conf_p2p_dev)
global->params.conf_p2p_dev =
@@ -4939,12 +5532,18 @@ int wpa_supplicant_run(struct wpa_global *global)
struct wpa_supplicant *wpa_s;
if (global->params.daemonize &&
- wpa_supplicant_daemon(global->params.pid_file))
+ (wpa_supplicant_daemon(global->params.pid_file) ||
+ eloop_sock_requeue()))
+ return -1;
+
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_supplicant_match_existing(global))
return -1;
+#endif
if (global->params.wait_for_monitor) {
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
- if (wpa_s->ctrl_iface)
+ if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
wpa_supplicant_ctrl_iface_wait(
wpa_s->ctrl_iface);
}
@@ -5010,6 +5609,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.ctrl_interface_group);
os_free(global->params.override_driver);
os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+ os_free(global->params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
os_free(global->params.conf_p2p_dev);
#endif /* CONFIG_P2P */
@@ -5042,6 +5644,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
wpas_init_ext_pw(wpa_s);
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
+ wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -5281,6 +5886,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
wpa_supplicant_req_scan(wpa_s, 0, 0);
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ if (eap->pending_ext_cert_check != PENDING_CHECK)
+ return -1;
+ if (os_strcmp(value, "good") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
+ else if (os_strcmp(value, "bad") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
+ else
+ return -1;
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
@@ -5350,6 +5965,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
return NO_MGMT_FRAME_PROTECTION;
}
+ if (ssid &&
+ (ssid->key_mgmt &
+ ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
+ WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
+ /*
+ * Do not use the default PMF value for non-RSN networks
+ * since PMF is available only with RSN and pmf=2
+ * configuration would otherwise prevent connections to
+ * all open networks.
+ */
+ return NO_MGMT_FRAME_PROTECTION;
+ }
+
return wpa_s->conf->pmf;
}
@@ -5508,6 +6136,27 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_s->reassociate = 0;
+ wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+}
+
+
void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
struct wpa_used_freq_data *freqs_data,
unsigned int len)
@@ -5690,11 +6339,19 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
#define ECANCELED -1
#endif
+/* Measurement Request element + Location Subject + Maximum Age subelement */
+#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
+/* Measurement Request element + Location Civic Request */
+#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
+
+
/**
* wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
* @wpa_s: Pointer to wpa_supplicant
* @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
* is sent in the request.
+ * @lci: if set, neighbor request will include LCI request
+ * @civic: if set, neighbor request will include civic location request
* @cb: Callback function to be called once the requested report arrives, or
* timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
* In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
@@ -5708,7 +6365,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
* Request must contain a callback function.
*/
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
+ const struct wpa_ssid_value *ssid,
+ int lci, int civic,
void (*cb)(void *ctx,
struct wpabuf *neighbor_rep),
void *cb_ctx)
@@ -5749,7 +6407,9 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
}
/* 3 = action category + action code + dialog token */
- buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
+ buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
+ (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
+ (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
if (buf == NULL) {
wpa_printf(MSG_DEBUG,
"RRM: Failed to allocate Neighbor Report Request");
@@ -5769,6 +6429,72 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
}
+ if (lci) {
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
+
+ /*
+ * Measurement token; nonzero number that is unique among the
+ * Measurement Request elements in a particular frame.
+ */
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+
+ /*
+ * Parallel, Enable, Request, and Report bits are 0, Duration is
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
+
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
+ /* Location Subject */
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+ /* Optional Subelements */
+ /*
+ * IEEE P802.11-REVmc/D5.0 Figure 9-170
+ * The Maximum Age subelement is required, otherwise the AP can
+ * send only data that was determined after receiving the
+ * request. Setting it here to unlimited age.
+ */
+ wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+ wpabuf_put_u8(buf, 2);
+ wpabuf_put_le16(buf, 0xffff);
+ }
+
+ if (civic) {
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
+
+ /*
+ * Measurement token; nonzero number that is unique among the
+ * Measurement Request elements in a particular frame.
+ */
+ wpabuf_put_u8(buf, 2); /* Measurement Token */
+
+ /*
+ * Parallel, Enable, Request, and Report bits are 0, Duration is
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ /* Measurement Type */
+ wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
+
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
+ * Location Civic request */
+ /* Location Subject */
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+ wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
+ /* Location Service Interval Units: Seconds */
+ wpabuf_put_u8(buf, 0);
+ /* Location Service Interval: 0 - Only one report is requested
+ */
+ wpabuf_put_le16(buf, 0);
+ /* No optional subelements */
+ }
+
wpa_s->rrm.next_neighbor_rep_token++;
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -5791,6 +6517,147 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
}
+static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
+ const u8 *request, size_t len,
+ struct wpabuf *report)
+{
+ u8 token, type, subject;
+ u16 max_age = 0;
+ struct os_reltime t, diff;
+ unsigned long diff_l;
+ u8 *ptoken;
+ const u8 *subelem;
+
+ if (!wpa_s->lci || len < 3 + 4)
+ return report;
+
+ token = *request++;
+ /* Measurement request mode isn't used */
+ request++;
+ type = *request++;
+ subject = *request++;
+
+ wpa_printf(MSG_DEBUG,
+ "Measurement request token %u type %u location subject %u",
+ token, type, subject);
+
+ if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) {
+ wpa_printf(MSG_INFO,
+ "Not building LCI report - bad type or location subject");
+ return report;
+ }
+
+ /* Subelements are formatted exactly like elements */
+ subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ max_age = WPA_GET_LE16(subelem + 2);
+
+ if (os_get_reltime(&t))
+ return report;
+
+ os_reltime_sub(&t, &wpa_s->lci_time, &diff);
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ if (max_age != 0xffff && max_age < diff_l)
+ return report;
+
+ if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci)))
+ return report;
+
+ wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(report, wpabuf_len(wpa_s->lci));
+ /* We'll override user's measurement token */
+ ptoken = wpabuf_put(report, 0);
+ wpabuf_put_buf(report, wpa_s->lci);
+ *ptoken = token;
+
+ return report;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len)
+{
+ struct wpabuf *buf, *report;
+ u8 token;
+ const u8 *ie, *end;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request: Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request: Not RRM network");
+ return;
+ }
+
+ if (len < 3) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring too short radio measurement request");
+ return;
+ }
+
+ end = frame + len;
+
+ token = *frame++;
+
+ /* Ignore number of repetitions because it's not used in LCI request */
+ frame += 2;
+
+ report = NULL;
+ while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) &&
+ ie[1] >= 3) {
+ u8 msmt_type;
+
+ msmt_type = ie[4];
+ wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type);
+
+ switch (msmt_type) {
+ case MEASURE_TYPE_LCI:
+ report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1],
+ report);
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "RRM: Unsupported radio measurement request %d",
+ msmt_type);
+ break;
+ }
+
+ frame = ie + ie[1] + 2;
+ }
+
+ if (!report)
+ return;
+
+ buf = wpabuf_alloc(3 + wpabuf_len(report));
+ if (!buf) {
+ wpabuf_free(report);
+ return;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+ wpabuf_put_u8(buf, token);
+
+ wpabuf_put_buf(buf, report);
+ wpabuf_free(report);
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0)) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Radio measurement report failed: Sending Action frame failed");
+ }
+ wpabuf_free(buf);
+}
+
+
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *frame, size_t len,
@@ -5868,3 +6735,175 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
}
wpabuf_free(buf);
}
+
+
+struct wpa_supplicant *
+wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
+{
+ switch (frame) {
+#ifdef CONFIG_P2P
+ case VENDOR_ELEM_PROBE_REQ_P2P:
+ case VENDOR_ELEM_PROBE_RESP_P2P:
+ case VENDOR_ELEM_PROBE_RESP_P2P_GO:
+ case VENDOR_ELEM_BEACON_P2P_GO:
+ case VENDOR_ELEM_P2P_PD_REQ:
+ case VENDOR_ELEM_P2P_PD_RESP:
+ case VENDOR_ELEM_P2P_GO_NEG_REQ:
+ case VENDOR_ELEM_P2P_GO_NEG_RESP:
+ case VENDOR_ELEM_P2P_GO_NEG_CONF:
+ case VENDOR_ELEM_P2P_INV_REQ:
+ case VENDOR_ELEM_P2P_INV_RESP:
+ case VENDOR_ELEM_P2P_ASSOC_REQ:
+ case VENDOR_ELEM_P2P_ASSOC_RESP:
+ return wpa_s->p2pdev;
+#endif /* CONFIG_P2P */
+ default:
+ return wpa_s;
+ }
+}
+
+
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+ char buf[30];
+
+ wpa_printf(MSG_DEBUG, "Update vendor elements");
+
+ for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
+ if (wpa_s->vendor_elem[i]) {
+ int res;
+
+ res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
+ if (!os_snprintf_error(sizeof(buf), res)) {
+ wpa_hexdump_buf(MSG_DEBUG, buf,
+ wpa_s->vendor_elem[i]);
+ }
+ }
+ }
+
+#ifdef CONFIG_P2P
+ if (wpa_s->parent == wpa_s &&
+ wpa_s->global->p2p &&
+ !wpa_s->global->p2p_disabled)
+ p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
+#endif /* CONFIG_P2P */
+}
+
+
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+ const u8 *elem, size_t len)
+{
+ u8 *ie, *end;
+
+ ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
+ end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
+
+ for (; ie + 1 < end; ie += 2 + ie[1]) {
+ if (ie + len > end)
+ break;
+ if (os_memcmp(ie, elem, len) != 0)
+ continue;
+
+ if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
+ wpabuf_free(wpa_s->vendor_elem[frame]);
+ wpa_s->vendor_elem[frame] = NULL;
+ } else {
+ os_memmove(ie, ie + len, end - (ie + len));
+ wpa_s->vendor_elem[frame]->used -= len;
+ }
+ wpas_vendor_elem_update(wpa_s);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes, enum hostapd_hw_mode mode)
+{
+ u16 i;
+
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode == mode)
+ return &modes[i];
+ }
+
+ return NULL;
+}
+
+
+static struct
+wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bss_tmp_disallowed *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0)
+ return bss;
+ }
+
+ return NULL;
+}
+
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ unsigned int sec)
+{
+ struct wpa_bss_tmp_disallowed *bss;
+ struct os_reltime until;
+
+ os_get_reltime(&until);
+ until.sec += sec;
+
+ bss = wpas_get_disallowed_bss(wpa_s, bssid);
+ if (bss) {
+ bss->disallowed_until = until;
+ return;
+ }
+
+ bss = os_malloc(sizeof(*bss));
+ if (!bss) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate memory for temp disallow BSS");
+ return;
+ }
+
+ bss->disallowed_until = until;
+ os_memcpy(bss->bssid, bssid, ETH_ALEN);
+ dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
+}
+
+
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ if (!os_reltime_before(&now, &tmp->disallowed_until)) {
+ /* This BSS is not disallowed anymore */
+ dl_list_del(&tmp->list);
+ os_free(tmp);
+ continue;
+ }
+ if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (!bss)
+ return 0;
+
+ os_reltime_sub(&bss->disallowed_until, &now, &age);
+ wpa_printf(MSG_DEBUG,
+ "BSS " MACSTR " disabled for %ld.%0ld seconds",
+ MAC2STR(bss->bssid), age.sec, age.usec);
+ return 1;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 6fe67e4..b3138e3 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -118,6 +118,25 @@ eapol_version=1
# networks are found, a new IBSS or AP mode network is created.
ap_scan=1
+# Whether to force passive scan for network connection
+#
+# By default, scans will send out Probe Request frames on channels that allow
+# active scanning. This advertise the local station to the world. Normally this
+# is fine, but users may wish to do passive scanning where the radio should only
+# listen quietly for Beacon frames and not send any Probe Request frames. Actual
+# functionality may be driver dependent.
+#
+# This parameter can be used to force only passive scanning to be used
+# for network connection cases. It should be noted that this will slow
+# down scan operations and reduce likelihood of finding the AP. In
+# addition, some use cases will override this due to functional
+# requirements, e.g., for finding an AP that uses hidden SSID
+# (scan_ssid=1) or P2P device discovery.
+#
+# 0: Do normal scans (allow active scans) (default)
+# 1: Do passive scans.
+#passive_scan=0
+
# MPM residency
# By default, wpa_supplicant implements the mesh peering manager (MPM) for an
# open mesh. However, if the driver can implement the MPM, you may set this to
@@ -149,10 +168,13 @@ ap_scan=1
fast_reauth=1
# OpenSSL Engine support
-# These options can be used to load OpenSSL engines.
+# These options can be used to load OpenSSL engines in special or legacy
+# modes.
# The two engines that are supported currently are shown below:
# They are both from the opensc project (http://www.opensc.org/)
-# By default no engines are loaded.
+# By default the PKCS#11 engine is loaded if the client_cert or
+# private_key option appear to be a PKCS#11 URI, and these options
+# should not need to be used explicitly.
# make the opensc engine available
#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
# make the pkcs11 engine available
@@ -178,7 +200,7 @@ fast_reauth=1
#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
# Driver interface parameters
-# This field can be used to configure arbitrary driver interace parameters. The
+# This field can be used to configure arbitrary driver interface parameters. The
# format is specific to the selected driver interface. This field is not used
# in most cases.
#driver_param="field=value"
@@ -295,7 +317,9 @@ fast_reauth=1
# up to the limit of 300 seconds (3, 9, 27 ... 300)
# For periodic module, parameters would be <fixed interval>
#autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan.
+# Note: If sched_scan_plans are configured and supported by the driver,
+# autoscan is ignored.
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
@@ -339,10 +363,12 @@ fast_reauth=1
# Protected Management Frames default
# This parameter can be used to set the default behavior for the ieee80211w
-# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
-# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
-# is enabled/required by default, but can be disabled with the per-network
-# ieee80211w parameter.
+# parameter for RSN networks. By default, PMF is disabled unless enabled with
+# the global pmf=1/2 parameter or with the per-network ieee80211w=1/2 parameter.
+# With pmf=1/2, PMF is enabled/required by default, but can be disabled with the
+# per-network ieee80211w parameter. This global default value does not apply
+# for non-RSN networks (key_mgmt=NONE) since PMF is available only when using
+# RSN.
#pmf=0
# Enabled SAE finite cyclic groups in preference order
@@ -417,6 +443,28 @@ fast_reauth=1
# matching network block
#auto_interworking=0
+# GAS Address3 field behavior
+# 0 = P2P specification (Address3 = AP BSSID); default
+# 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+# sent to not-associated AP; if associated, AP BSSID)
+#gas_address3=0
+
+# Publish fine timing measurement (FTM) responder functionality in
+# the Extended Capabilities element bit 70.
+# Controls whether FTM responder functionality will be published by AP/STA.
+# Note that actual FTM responder operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality in
+# the Extended Capabilities element bit 71.
+# Controls whether FTM initiator functionality will be published by AP/STA.
+# Note that actual FTM initiator operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_initiator=0
+
# credential block
#
# Each credential used for automatic network selection is configured as a set
@@ -451,6 +499,10 @@ fast_reauth=1
# (EAP-TLS). Full path to the file should be used since working
# directory may change when wpa_supplicant is run in the background.
#
+# Certificates from PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#
+# For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
# Alternatively, a named configuration blob can be used by setting
# this to blob://blob_name.
#
@@ -461,6 +513,9 @@ fast_reauth=1
# used since working directory may change when wpa_supplicant is run
# in the background.
#
+# Keys in PKCS#11 tokens can be referenced by a PKCS#11 URI.
+# For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
# Windows certificate store can be used by leaving client_cert out and
# configuring private_key in one of the following formats:
#
@@ -565,6 +620,8 @@ fast_reauth=1
# 0 = do not use OCSP stapling (TLS certificate status extension)
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
+# 3 = require valid OCSP stapling response for all not-trusted
+# certificates in the server certificate chain
#
# sim_num: Identifier for which SIM to use in multi-SIM devices
#
@@ -597,6 +654,41 @@ fast_reauth=1
# Hotspot 2.0
# hs20=1
+# Scheduled scan plans
+#
+# A space delimited list of scan plans. Each scan plan specifies the scan
+# interval and number of iterations, delimited by a colon. The last scan plan
+# will run infinitely and thus must specify only the interval and not the number
+# of iterations.
+#
+# The driver advertises the maximum number of scan plans supported. If more scan
+# plans than supported are configured, only the first ones are set (up to the
+# maximum supported). The last scan plan that specifies only the interval is
+# always set as the last plan.
+#
+# If the scan interval or the number of iterations for a scan plan exceeds the
+# maximum supported, it will be set to the maximum supported value.
+#
+# Format:
+# sched_scan_plans=<interval:iterations> <interval:iterations> ... <interval>
+#
+# Example:
+# sched_scan_plans=10:100 20:200 30
+
+# Multi Band Operation (MBO) non-preferred channels
+# A space delimited list of non-preferred channels where each channel is a colon
+# delimited list of values.
+# Format:
+# non_pref_chan=<oper_class>:<chan>:<preference>:<reason>
+# Example:
+# non_pref_chan="81:5:10:2 81:1:0:2 81:9:0:2"
+
+# MBO Cellular Data Capabilities
+# 1 = Cellular data connection available
+# 2 = Cellular data connection not available
+# 3 = Not cellular capable (default)
+#mbo_cell_capa=3
+
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -658,6 +750,17 @@ fast_reauth=1
# an IBSS network with the configured SSID is already present, the frequency of
# the network will be used instead of this configured value.
#
+# pbss: Whether to use PBSS. Relevant to IEEE 802.11ad networks only.
+# 0 = do not use PBSS
+# 1 = use PBSS
+# 2 = don't care (not allowed in AP mode)
+# Used together with mode configuration. When mode is AP, it means to start a
+# PCP instead of a regular AP. When mode is infrastructure it means connect
+# to a PCP instead of AP. In this mode you can also specify 2 (don't care)
+# which means connect to either PCP or AP.
+# P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in IEEE 802.11ad network.
+# For more details, see IEEE Std 802.11ad-2012.
+#
# scan_freq: List of frequencies to scan
# Space-separated list of frequencies in MHz to scan when searching for this
# BSS. If the subset of channels used by the network is known, this option can
@@ -706,8 +809,19 @@ fast_reauth=1
# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
# generated WEP keys
# NONE = WPA is not used; plaintext or static WEP could be used
+# WPA-NONE = WPA-None for IBSS (deprecated; use proto=RSN key_mgmt=WPA-PSK
+# instead)
+# FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
+# FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+# SAE = Simultaneous authentication of equals; pre-shared key/password -based
+# authentication with stronger security than WPA-PSK especially when using
+# not that strong password
+# FT-SAE = SAE with FT
+# WPA-EAP-SUITE-B = Suite B 128-bit level
+# WPA-EAP-SUITE-B-192 = Suite B 192-bit level
+# OSEN = Hotspot 2.0 Rel 2 online signup connection
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# ieee80211w: whether management frame protection is enabled
@@ -798,9 +912,13 @@ fast_reauth=1
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
+# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
+# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
+# Authenticator role in IBSS.
+#
# Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods
-# MD5 = EAP-MD5 (unsecure and does not generate keying material ->
+# MD5 = EAP-MD5 (insecure and does not generate keying material ->
# cannot be used with WPA; to be used as a Phase 2 method
# with EAP-PEAP or EAP-TTLS)
# MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
@@ -891,23 +1009,23 @@ fast_reauth=1
# automatically converted into DH params.
# subject_match: Substring to be matched against the subject of the
# authentication server certificate. If this string is set, the server
-# sertificate is only accepted if it contains this string in the subject.
+# certificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
-# Note: Since this is a substring match, this cannot be used securily to
+# Note: Since this is a substring match, this cannot be used securely to
# do a suffix match against a possible domain name in the CN entry. For
# such a use case, domain_suffix_match or domain_match should be used
# instead.
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
-# If this string is set, the server sertificate is only accepted if it
+# If this string is set, the server certificate is only accepted if it
# contains one of the entries in an alternative subject name extension.
# altSubjectName string is in following format: TYPE:VALUE
# Example: EMAIL:server@example.com
# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
# domain_suffix_match: Constraint for server domain name. If set, this FQDN is
-# used as a suffix match requirement for the AAAserver certificate in
+# used as a suffix match requirement for the AAA server certificate in
# SubjectAltName dNSName element(s). If a matching dNSName is found, this
# constraint is met. If no dNSName values are present, this constraint is
# matched against SubjectName CN using same suffix match comparison.
@@ -995,6 +1113,12 @@ fast_reauth=1
# that have issues interoperating with updated TLS version)
# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_ext_cert_check=0 - No external server certificate validation (default)
+# tls_ext_cert_check=1 - External server certificate validation enabled; this
+# requires an external program doing validation of server certificate
+# chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control
+# interface and report the result of the validation with
+# CTRL-RSP_EXT_CERT_CHECK.
#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
@@ -1026,6 +1150,8 @@ fast_reauth=1
# 0 = do not use OCSP stapling (TLS certificate status extension)
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
+# 3 = require valid OCSP stapling response for all not-trusted
+# certificates in the server certificate chain
#
# openssl_ciphers: OpenSSL specific cipher configuration
# This can be used to override the global openssl_ciphers configuration
@@ -1059,6 +1185,9 @@ fast_reauth=1
# number of authentication servers. Strict EAP conformance mode can be
# configured by disabling workarounds with eap_workaround=0.
+# update_identifier: PPS MO ID
+# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+
# Station inactivity limit
#
# If a station does not send anything in ap_max_inactivity seconds, an
@@ -1082,6 +1211,11 @@ fast_reauth=1
# Beacon interval (default: 100 TU)
#beacon_int=100
+# WPS in AP mode
+# 0 = WPS enabled and configured (default)
+# 1 = WPS disabled
+#wps_disabled=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -1144,13 +1278,13 @@ fast_reauth=1
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
-# option CONFIG_FST is set while compiling hostapd. They allow this interface
-# to be a part of FST setup.
+# option CONFIG_FST is set while compiling wpa_supplicant. They allow this
+# interface to be a part of FST setup.
#
# FST is the transfer of a session from a channel to another channel, in the
# same or different frequency bands.
#
-# For detals, see IEEE Std 802.11ad-2012.
+# For details, see IEEE Std 802.11ad-2012.
# Identifier of an FST Group the interface belongs to.
#fst_group_id=bond0
@@ -1483,22 +1617,10 @@ network={
group=CCMP TKIP
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
- client_cert="/etc/cert/user.pem"
-
- engine=1
-
- # The engine configured here must be available. Look at
- # OpenSSL engine support in the global section.
- # The key available through the engine must be the private key
- # matching the client certificate configured above.
-
- # use the opensc engine
- #engine_id="opensc"
- #key_id="45"
- # use the pkcs11 engine
- engine_id="pkcs11"
- key_id="id_45"
+ # Certificate and/or key identified by PKCS#11 URI (RFC7512)
+ client_cert="pkcs11:manufacturer=piv_II;id=%01"
+ private_key="pkcs11:manufacturer=piv_II;id=%01"
# Optional PIN configuration; this can be left out and PIN will be
# asked through the control interface
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 58df48c..ef9273d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -44,6 +44,7 @@ struct wpa_driver_associate_params;
struct ctrl_iface_priv;
struct ctrl_iface_global_priv;
struct wpas_dbus_priv;
+struct wpas_binder_priv;
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
@@ -228,6 +229,17 @@ struct wpa_params {
char *conf_p2p_dev;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ /**
+ * match_ifaces - Interface descriptions to match
+ */
+ struct wpa_interface *match_ifaces;
+
+ /**
+ * match_iface_count - Number of defined matching interfaces
+ */
+ int match_iface_count;
+#endif /* CONFIG_MATCH_IFACE */
};
struct p2p_srv_bonjour {
@@ -253,6 +265,7 @@ struct wpa_global {
struct wpa_params params;
struct ctrl_iface_global_priv *ctrl_iface;
struct wpas_dbus_priv *dbus;
+ struct wpas_binder_priv *binder;
void **drv_priv;
size_t drv_count;
struct os_time suspend_time;
@@ -278,6 +291,7 @@ struct wpa_global {
unsigned int p2p_24ghz_social_channels:1;
unsigned int pending_p2ps_group:1;
unsigned int pending_group_iface_for_p2ps:1;
+ unsigned int pending_p2ps_group_freq;
#ifdef CONFIG_WIFI_DISPLAY
int wifi_display;
@@ -300,10 +314,14 @@ struct wpa_radio {
char name[16]; /* from driver_ops get_radio_name() or empty if not
* available */
unsigned int external_scan_running:1;
+ unsigned int num_active_works;
struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
struct dl_list work; /* struct wpa_radio_work::list entries */
};
+#define MAX_ACTIVE_WORKS 2
+
+
/**
* struct wpa_radio_work - Radio work item
*/
@@ -316,6 +334,7 @@ struct wpa_radio_work {
void *ctx;
unsigned int started:1;
struct os_reltime time;
+ unsigned int bands;
};
int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
@@ -347,6 +366,9 @@ struct wpa_external_work {
unsigned int timeout;
};
+enum wpa_radio_work_band wpas_freq_to_band(int freq);
+unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs);
+
/**
* offchannel_send_action_result - Result of offchannel send Action frame
*/
@@ -371,11 +393,6 @@ struct wps_ap_info {
u8 uuid[WPS_UUID_LEN];
};
-struct wpa_ssid_value {
- u8 ssid[SSID_MAX_LEN];
- size_t ssid_len;
-};
-
#define WPA_FREQ_USED_BY_INFRA_STATION BIT(0)
#define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1)
@@ -414,6 +431,21 @@ enum wpa_supplicant_test_failure {
WPAS_TEST_FAILURE_SCAN_TRIGGER,
};
+struct icon_entry {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ u8 dialog_token;
+ char *file_name;
+ u8 *image;
+ size_t image_len;
+};
+
+struct wpa_bss_tmp_disallowed {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ struct os_reltime disallowed_until;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -427,12 +459,16 @@ struct wpa_supplicant {
struct wpa_radio *radio; /* shared radio context */
struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */
struct wpa_supplicant *parent;
+ struct wpa_supplicant *p2pdev;
struct wpa_supplicant *next;
struct l2_packet_data *l2;
struct l2_packet_data *l2_br;
unsigned char own_addr[ETH_ALEN];
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
+#ifdef CONFIG_MATCH_IFACE
+ int matched;
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_CTRL_IFACE_DBUS
char *dbus_path;
#endif /* CONFIG_CTRL_IFACE_DBUS */
@@ -443,6 +479,9 @@ struct wpa_supplicant {
char *preq_notify_peer;
#endif /* CONFIG_AP */
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_BINDER
+ const void *binder_object_key;
+#endif /* CONFIG_CTRL_IFACE_BINDER */
char bridge_ifname[16];
char *confname;
@@ -455,7 +494,8 @@ struct wpa_supplicant {
u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
* field contains the target BSSID. */
int reassociate; /* reassociation requested */
- int reassoc_same_bss; /* reassociating to the same bss */
+ unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
+ unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
struct wpa_ssid *current_ssid;
@@ -500,9 +540,10 @@ struct wpa_supplicant {
struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
int sched_scan_timeout;
- int sched_scan_interval;
int first_sched_scan;
int sched_scan_timed_out;
+ struct sched_scan_plan *sched_scan_plans;
+ size_t sched_scan_plans_num;
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -533,6 +574,7 @@ struct wpa_supplicant {
struct wpa_radio_work *scan_work;
int scanning;
int sched_scanning;
+ unsigned int sched_scan_stop_req:1;
int new_connection;
int eapol_received; /* number of EAPOL packets received after the
@@ -613,6 +655,7 @@ struct wpa_supplicant {
#define MAX_SCAN_ID 16
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
+ u8 next_scan_bssid[ETH_ALEN];
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
@@ -634,6 +677,9 @@ struct wpa_supplicant {
int max_scan_ssids;
int max_sched_scan_ssids;
+ unsigned int max_sched_scan_plans;
+ unsigned int max_sched_scan_plan_interval;
+ unsigned int max_sched_scan_plan_iterations;
int sched_scan_supported;
unsigned int max_match_sets;
unsigned int max_remain_on_chan;
@@ -658,6 +704,7 @@ struct wpa_supplicant {
unsigned int reattach:1; /* reassociation to the same BSS requested */
unsigned int mac_addr_changed:1;
unsigned int added_vif:1;
+ unsigned int wnmsleep_used:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -722,7 +769,7 @@ struct wpa_supplicant {
int mesh_if_idx;
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
- int mesh_auth_block_duration; /* sec */
+ unsigned int mesh_vht_enabled:1;
#endif /* CONFIG_MESH */
unsigned int off_channel_freq;
@@ -844,6 +891,10 @@ struct wpa_supplicant {
int *p2p_group_common_freqs;
unsigned int p2p_group_common_freqs_num;
u8 p2ps_join_addr[ETH_ALEN];
+
+ unsigned int p2p_go_max_oper_chwidth;
+ unsigned int p2p_go_vht_center_freq2;
+ int p2p_lo_started;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
@@ -885,6 +936,7 @@ struct wpa_supplicant {
unsigned int fetch_osu_icon_in_progress:1;
struct wpa_bss *interworking_gas_bss;
unsigned int osu_icon_id;
+ struct dl_list icon_head; /* struct icon_entry */
struct osu_provider *osu_prov;
size_t osu_prov_count;
struct os_reltime osu_icon_fetch_start;
@@ -914,6 +966,9 @@ struct wpa_supplicant {
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
+ /* WLAN_STATUS_* status codes from (Re)Association Response frame. */
+ u16 assoc_status_code;
+
struct ext_password_data *ext_pw;
struct wpabuf *last_gas_resp, *prev_gas_resp;
@@ -969,6 +1024,10 @@ struct wpa_supplicant {
struct l2_packet_data *l2_test;
unsigned int extra_roc_dur;
enum wpa_supplicant_test_failure test_failure;
+ unsigned int reject_btm_req_reason;
+ unsigned int p2p_go_csa_on_inv:1;
+ unsigned int ignore_auth_resp:1;
+ unsigned int ignore_assoc_disallow:1;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -985,6 +1044,31 @@ struct wpa_supplicant {
const struct wpabuf *fst_ies;
struct wpabuf *received_mb_ies;
#endif /* CONFIG_FST */
+
+#ifdef CONFIG_MBO
+ /* Multiband operation non-preferred channel */
+ struct wpa_mbo_non_pref_channel {
+ enum mbo_non_pref_chan_reason reason;
+ u8 oper_class;
+ u8 chan;
+ u8 preference;
+ } *non_pref_chan;
+ size_t non_pref_chan_num;
+ u8 mbo_wnm_token;
+#endif /* CONFIG_MBO */
+
+ /*
+ * This should be under CONFIG_MBO, but it is left out to allow using
+ * the bss_temp_disallowed list for other purposes as well.
+ */
+ struct dl_list bss_tmp_disallowed;
+
+ /*
+ * Content of a measurement report element with type 8 (LCI),
+ * own location.
+ */
+ struct wpabuf *lci;
+ struct os_reltime lci_time;
};
@@ -1026,6 +1110,8 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code);
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1050,6 +1136,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s);
void wpa_show_license(void);
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+ const char *ifname);
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
struct wpa_interface *iface,
struct wpa_supplicant *parent);
@@ -1079,6 +1167,7 @@ int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
size_t ssid_len);
void wpas_request_connection(struct wpa_supplicant *wpa_s);
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
@@ -1088,15 +1177,37 @@ void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
const u8 *report, size_t report_len);
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
+ const struct wpa_ssid_value *ssid,
+ int lci, int civic,
void (*cb)(void *ctx,
struct wpabuf *neighbor_rep),
void *cb_ctx);
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len);
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *frame, size_t len,
int rssi);
+
+/* MBO functions */
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len);
+const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
+ const char *non_pref_chan);
+void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
+int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+ size_t len);
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
+ size_t len);
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+ size_t len,
+ enum mbo_transition_reject_reason reason);
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa);
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss);
+
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
* @wpa_s: Pointer to wpa_supplicant data
@@ -1158,6 +1269,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s);
+struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s,
+ enum wpa_vendor_elem_frame frame);
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+ const u8 *elem, size_t len);
+
#ifdef CONFIG_FST
struct fst_wpa_obj;
@@ -1167,4 +1284,18 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FST */
+int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
+
+struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes, enum hostapd_hw_mode mode);
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ unsigned int sec);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+
+struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+ int i, struct wpa_bss *bss,
+ struct wpa_ssid *group,
+ int only_first_ssid);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 29c22ba..f84c8b9 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -739,6 +739,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
return WPA_CTRL_REQ_SIM;
else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
return WPA_CTRL_REQ_PSK_PASSPHRASE;
+ else if (os_strcmp(field, "EXT_CERT_CHECK") == 0)
+ return WPA_CTRL_REQ_EXT_CERT_CHECK;
return WPA_CTRL_REQ_UNKNOWN;
}
@@ -782,6 +784,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
*txt = "PSK or passphrase";
ret = "PSK_PASSPHRASE";
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ *txt = "External server certificate validation";
+ ret = "EXT_CERT_CHECK";
+ break;
default:
break;
}
@@ -837,6 +843,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
if (ssid == NULL)
return;
+ if (field == WPA_CTRL_REQ_EXT_CERT_CHECK)
+ ssid->eap.pending_ext_cert_check = PENDING_CHECK;
wpas_notify_network_request(wpa_s, ssid, field, default_txt);
field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
@@ -1013,7 +1021,6 @@ static void wpa_supplicant_set_rekey_offload(void *ctx,
wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr);
}
-#endif /* CONFIG_NO_WPA */
static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
@@ -1028,6 +1035,7 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
else
return 0;
}
+#endif /* CONFIG_NO_WPA */
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
@@ -1124,6 +1132,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
}
}
#endif /* CONFIG_P2P */
+ conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index 354decf..d6ec8c5 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -50,10 +50,9 @@ static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
}
-static int wpas_set_current_cipher_suite(void *wpa_s, const u8 *cs,
- size_t cs_len)
+static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
{
- return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len);
+ return wpa_drv_set_current_cipher_suite(wpa_s, cs);
}
@@ -109,7 +108,8 @@ static int wpas_create_receive_sc(void *wpa_s, u32 channel,
enum validate_frames vf,
enum confidentiality_offset co)
{
- return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, sci->port,
+ return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr,
+ be_to_host16(sci->port),
conf_offset_val(co), vf);
}
@@ -150,7 +150,8 @@ wpas_create_transmit_sc(void *wpa_s, u32 channel,
const struct ieee802_1x_mka_sci *sci,
enum confidentiality_offset co)
{
- return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, sci->port,
+ return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr,
+ be_to_host16(sci->port),
conf_offset_val(co));
}
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 6af1678..4e37591 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "wpa_supplicant_i.h"
#include "blacklist.h"
@@ -79,30 +80,18 @@ int wpas_module_tests(void)
ret = -1;
#ifdef CONFIG_WPS
- {
- int wps_module_tests(void);
- if (wps_module_tests() < 0)
- ret = -1;
- }
+ if (wps_module_tests() < 0)
+ ret = -1;
#endif /* CONFIG_WPS */
- {
- int utils_module_tests(void);
- if (utils_module_tests() < 0)
- ret = -1;
- }
-
- {
- int common_module_tests(void);
- if (common_module_tests() < 0)
- ret = -1;
- }
-
- {
- int crypto_module_tests(void);
- if (crypto_module_tests() < 0)
- ret = -1;
- }
+ if (utils_module_tests() < 0)
+ ret = -1;
+
+ if (common_module_tests() < 0)
+ ret = -1;
+
+ if (crypto_module_tests() < 0)
+ ret = -1;
return ret;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 60f761c..74a420c 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -583,8 +583,8 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
m2d->dev_password_id, m2d->config_error);
wpas_notify_wps_event_m2d(wpa_s, m2d);
#ifdef CONFIG_P2P
- if (wpa_s->parent && wpa_s->parent != wpa_s) {
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
"dev_password_id=%d config_error=%d",
m2d->dev_password_id, m2d->config_error);
}
@@ -617,8 +617,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
wps_ei_str(fail->error_indication));
- if (wpa_s->parent && wpa_s->parent != wpa_s)
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error,
fail->error_indication,
@@ -627,8 +627,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
fail->msg, fail->config_error);
- if (wpa_s->parent && wpa_s->parent != wpa_s)
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
@@ -683,6 +683,13 @@ static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
}
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+ return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
+ wpa_s, NULL);
+}
+
+
static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
@@ -1135,6 +1142,13 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
return -1;
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
#ifdef CONFIG_P2P
if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
@@ -1142,6 +1156,10 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
ssid->ssid_len = wpa_s->go_params->ssid_len;
os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
ssid->ssid_len);
+ if (wpa_s->go_params->freq > 56160) {
+ /* P2P in 60 GHz uses PBSS */
+ ssid->pbss = 1;
+ }
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1186,6 +1204,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
}
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
if (ssid_val) {
ssid->ssid = os_malloc(ssid_len);
if (ssid->ssid) {
@@ -1209,6 +1234,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
ssid->ssid_len = wpa_s->go_params->ssid_len;
os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
ssid->ssid_len);
+ if (wpa_s->go_params->freq > 56160) {
+ /* P2P in 60 GHz uses PBSS */
+ ssid->pbss = 1;
+ }
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1221,7 +1250,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
dev_pw_id, hash);
} else {
- rpin = wps_generate_pin();
+ if (wps_generate_pin(&rpin) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
+ return -1;
+ }
os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
rpin, dev_pw_id, hash);
}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 3c25ca8..c8fe47e 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -85,6 +85,7 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WPS */
@@ -147,6 +148,12 @@ static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
{
}
+static inline int
+wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_SUPPLICANT_H */