summaryrefslogtreecommitdiff
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorStefan Lippers-Hollmann <s.l-h@gmx.de>2014-06-29 23:18:53 +0000
committerAndrew Shadura <andrewsh@debian.org>2016-07-20 21:37:01 +0200
commit3a03694454bbec18114240b108a0af232133766b (patch)
treeade1c03a378de7430ac902dab71fb96576508eb6 /wpa_supplicant
parentc2af19e367fc0d1abca6a52d00b239618e8c6186 (diff)
Imported Upstream version 2.1
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/Android.mk271
-rw-r--r--wpa_supplicant/ChangeLog415
-rw-r--r--wpa_supplicant/Makefile274
-rw-r--r--wpa_supplicant/README217
-rw-r--r--wpa_supplicant/README-HS20507
-rw-r--r--wpa_supplicant/README-P2P105
-rw-r--r--wpa_supplicant/README-WPS116
-rw-r--r--wpa_supplicant/README-Windows.txt155
-rw-r--r--wpa_supplicant/android.config481
-rw-r--r--wpa_supplicant/ap.c437
-rw-r--r--wpa_supplicant/ap.h43
-rw-r--r--wpa_supplicant/autoscan.c143
-rw-r--r--wpa_supplicant/autoscan.h49
-rw-r--r--wpa_supplicant/autoscan_exponential.c104
-rw-r--r--wpa_supplicant/autoscan_periodic.c85
-rw-r--r--wpa_supplicant/bgscan.c16
-rw-r--r--wpa_supplicant/bgscan.h15
-rw-r--r--wpa_supplicant/bgscan_learn.c55
-rw-r--r--wpa_supplicant/bgscan_simple.c45
-rw-r--r--wpa_supplicant/blacklist.c24
-rw-r--r--wpa_supplicant/blacklist.h10
-rw-r--r--wpa_supplicant/bss.c645
-rw-r--r--wpa_supplicant/bss.h97
-rw-r--r--wpa_supplicant/config.c1221
-rw-r--r--wpa_supplicant/config.h525
-rw-r--r--wpa_supplicant/config_file.c378
-rw-r--r--wpa_supplicant/config_none.c19
-rw-r--r--wpa_supplicant/config_ssid.h227
-rw-r--r--wpa_supplicant/config_winreg.c46
-rw-r--r--wpa_supplicant/ctrl_iface.c3586
-rw-r--r--wpa_supplicant/ctrl_iface.h16
-rw-r--r--wpa_supplicant/ctrl_iface_named_pipe.c12
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c61
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c694
-rw-r--r--wpa_supplicant/dbus/Makefile2
-rw-r--r--wpa_supplicant/dbus/dbus_common.c35
-rw-r--r--wpa_supplicant/dbus/dbus_common.h10
-rw-r--r--wpa_supplicant/dbus/dbus_common_i.h14
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.c32
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.h10
-rw-r--r--wpa_supplicant/dbus/dbus_new.c367
-rw-r--r--wpa_supplicant/dbus/dbus_new.h58
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c844
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h62
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c112
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h12
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_wps.c12
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.c16
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.h10
-rw-r--r--wpa_supplicant/dbus/dbus_new_introspect.c10
-rw-r--r--wpa_supplicant/dbus/dbus_old.c13
-rw-r--r--wpa_supplicant/dbus/dbus_old.h10
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.c32
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.h10
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers_wps.c10
-rw-r--r--wpa_supplicant/defconfig171
-rw-r--r--wpa_supplicant/doc/docbook/Makefile3
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.sgml205
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml23
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml186
-rw-r--r--wpa_supplicant/driver_i.h232
-rw-r--r--wpa_supplicant/eap_proxy_dummy.mk0
-rw-r--r--wpa_supplicant/eap_register.c26
-rw-r--r--wpa_supplicant/eapol_test.c176
-rw-r--r--wpa_supplicant/events.c1797
-rw-r--r--wpa_supplicant/examples/dbus-listen-preq.py62
-rwxr-xr-xwpa_supplicant/examples/p2p-action.sh15
-rw-r--r--wpa_supplicant/examples/p2p-nfc.py581
-rw-r--r--wpa_supplicant/examples/p2p/p2p_connect.py299
-rw-r--r--wpa_supplicant/examples/p2p/p2p_disconnect.py169
-rw-r--r--wpa_supplicant/examples/p2p/p2p_find.py192
-rw-r--r--wpa_supplicant/examples/p2p/p2p_flush.py168
-rw-r--r--wpa_supplicant/examples/p2p/p2p_group_add.py222
-rw-r--r--wpa_supplicant/examples/p2p/p2p_invite.py201
-rw-r--r--wpa_supplicant/examples/p2p/p2p_listen.py182
-rw-r--r--wpa_supplicant/examples/p2p/p2p_stop_find.py174
-rw-r--r--wpa_supplicant/examples/wps-ap-cli78
-rw-r--r--wpa_supplicant/examples/wps-nfc.py460
-rw-r--r--wpa_supplicant/gas_query.c256
-rw-r--r--wpa_supplicant/gas_query.h16
-rw-r--r--wpa_supplicant/hs20_supplicant.c214
-rw-r--r--wpa_supplicant/hs20_supplicant.h22
-rw-r--r--wpa_supplicant/ibss_rsn.c396
-rw-r--r--wpa_supplicant/ibss_rsn.h30
-rw-r--r--wpa_supplicant/interworking.c1537
-rw-r--r--wpa_supplicant/interworking.h22
-rw-r--r--wpa_supplicant/main.c109
-rw-r--r--wpa_supplicant/main_none.c10
-rw-r--r--wpa_supplicant/main_symbian.cpp48
-rw-r--r--wpa_supplicant/main_winmain.c10
-rw-r--r--wpa_supplicant/main_winsvc.c10
-rw-r--r--wpa_supplicant/nfc_pw_token.c83
-rw-r--r--wpa_supplicant/notify.c57
-rw-r--r--wpa_supplicant/notify.h16
-rw-r--r--wpa_supplicant/offchannel.c118
-rw-r--r--wpa_supplicant/offchannel.h12
-rw-r--r--wpa_supplicant/p2p_supplicant.c4549
-rw-r--r--wpa_supplicant/p2p_supplicant.h117
-rw-r--r--wpa_supplicant/preauth_test.c22
-rw-r--r--wpa_supplicant/scan.c976
-rw-r--r--wpa_supplicant/scan.h32
-rw-r--r--wpa_supplicant/sme.c685
-rw-r--r--wpa_supplicant/sme.h27
-rw-r--r--wpa_supplicant/symbian/README.symbian24
-rw-r--r--wpa_supplicant/symbian/bld.inf8
-rw-r--r--wpa_supplicant/symbian/wpa_supplicant.mmp38
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in (renamed from wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in)2
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in (renamed from wpa_supplicant/systemd/wpa_supplicant-wired@.service.in)2
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant.service.arg.in (renamed from wpa_supplicant/systemd/wpa_supplicant@.service.in)2
-rw-r--r--wpa_supplicant/tests/test_eap_sim_common.c12
-rw-r--r--wpa_supplicant/tests/test_wpa.c18
-rwxr-xr-xwpa_supplicant/utils/log2pcap.py54
-rwxr-xr-xwpa_supplicant/vs2005/eapol_test/eapol_test.vcproj4
-rwxr-xr-xwpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj4
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj4
-rwxr-xr-xwpa_supplicant/vs2005/wpasvc/wpasvc.vcproj4
-rw-r--r--wpa_supplicant/wifi_display.c292
-rw-r--r--wpa_supplicant/wifi_display.h21
-rw-r--r--wpa_supplicant/win_if_list.c10
-rw-r--r--wpa_supplicant/wnm_sta.c789
-rw-r--r--wpa_supplicant/wnm_sta.h87
-rw-r--r--wpa_supplicant/wpa_cli.c2255
-rw-r--r--wpa_supplicant/wpa_gui-qt4/addinterface.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/addinterface.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/main.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.cpp14
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/signalbar.cpp58
-rw-r--r--wpa_supplicant/wpa_gui-qt4/signalbar.h28
-rw-r--r--wpa_supplicant/wpa_gui-qt4/stringquery.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/stringquery.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpa_gui.pro2
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.cpp22
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.h10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpamsg.h10
-rw-r--r--wpa_supplicant/wpa_gui/.gitignore3
-rw-r--r--wpa_supplicant/wpa_gui/eventhistory.ui125
-rw-r--r--wpa_supplicant/wpa_gui/eventhistory.ui.h41
-rw-r--r--wpa_supplicant/wpa_gui/main.cpp30
-rw-r--r--wpa_supplicant/wpa_gui/networkconfig.ui475
-rw-r--r--wpa_supplicant/wpa_gui/networkconfig.ui.h552
-rw-r--r--wpa_supplicant/wpa_gui/scanresults.ui179
-rw-r--r--wpa_supplicant/wpa_gui/scanresults.ui.h101
-rwxr-xr-xwpa_supplicant/wpa_gui/setup-mingw-cross-compiling11
-rw-r--r--wpa_supplicant/wpa_gui/userdatarequest.ui163
-rw-r--r--wpa_supplicant/wpa_gui/userdatarequest.ui.h72
-rw-r--r--wpa_supplicant/wpa_gui/wpa_gui.pro50
-rw-r--r--wpa_supplicant/wpa_gui/wpagui.ui471
-rw-r--r--wpa_supplicant/wpa_gui/wpagui.ui.h730
-rw-r--r--wpa_supplicant/wpa_gui/wpamsg.h34
-rw-r--r--wpa_supplicant/wpa_passphrase.c12
-rw-r--r--wpa_supplicant/wpa_priv.c20
-rw-r--r--wpa_supplicant/wpa_supplicant.c2120
-rw-r--r--wpa_supplicant/wpa_supplicant.conf404
-rw-r--r--wpa_supplicant/wpa_supplicant.nsi112
-rw-r--r--wpa_supplicant/wpa_supplicant_conf.mk34
-rw-r--r--wpa_supplicant/wpa_supplicant_conf.sh16
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h399
-rw-r--r--wpa_supplicant/wpa_supplicant_template.conf6
-rw-r--r--wpa_supplicant/wpas_glue.c171
-rw-r--r--wpa_supplicant/wpas_glue.h10
-rw-r--r--wpa_supplicant/wps_supplicant.c1409
-rw-r--r--wpa_supplicant/wps_supplicant.h64
-rw-r--r--wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj513
176 files changed, 30129 insertions, 9907 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 40fde34..9b07460 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1,39 +1,47 @@
#
# Copyright (C) 2008 The Android Open Source Project
#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
#
LOCAL_PATH := $(call my-dir)
PKG_CONFIG ?= pkg-config
-WPA_BUILD_SUPPLICANT := false
-ifneq ($(TARGET_SIMULATOR),true)
- ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
- WPA_BUILD_SUPPLICANT := true
- CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
- endif
+ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
+ CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
+else
+ CONFIG_DRIVER_TEST := y
endif
-include $(LOCAL_PATH)/.config
+include $(LOCAL_PATH)/android.config
# To ignore possible wrong network configurations
L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
# Set Android log name
L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\"
+# Disable roaming in wpa_supplicant
+ifdef CONFIG_NO_ROAMING
+L_CFLAGS += -DCONFIG_NO_ROAMING
+endif
+
+ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
+L_CFLAGS += -DANDROID_P2P
+L_CFLAGS += -DP2P_CONCURRENT_SEARCH_DELAY=0
+endif
+
+ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
+L_CFLAGS += -DANDROID_P2P
+endif
+
+ifeq ($(BOARD_WLAN_DEVICE), mrvl)
+L_CFLAGS += -DANDROID_P2P
+endif
+
# Use Android specific directory for control interface sockets
L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\"
@@ -43,12 +51,6 @@ ifeq ($(TARGET_ARCH),arm)
L_CFLAGS += -mabi=aapcs-linux
endif
-# To allow non-ASCII characters in SSID
-L_CFLAGS += -DWPA_UNICODE_SSID
-
-# OpenSSL is configured without engines on Android
-L_CFLAGS += -DOPENSSL_NO_ENGINE
-
INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/src
INCLUDES += $(LOCAL_PATH)/src/common
@@ -66,11 +68,16 @@ INCLUDES += $(LOCAL_PATH)/src/tls
INCLUDES += $(LOCAL_PATH)/src/utils
INCLUDES += $(LOCAL_PATH)/src/wps
INCLUDES += external/openssl/include
-INCLUDES += frameworks/base/cmds/keystore
+INCLUDES += system/security/keystore/include
ifdef CONFIG_DRIVER_NL80211
INCLUDES += external/libnl-headers
endif
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.c
OBJS += notify.c
OBJS += bss.c
@@ -125,11 +132,22 @@ endif
OBJS += src/utils/$(CONFIG_ELOOP).c
OBJS_c += src/utils/$(CONFIG_ELOOP).c
+ifdef CONFIG_ELOOP_POLL
+L_CFLAGS += -DCONFIG_ELOOP_POLL
+endif
ifdef CONFIG_EAPOL_TEST
L_CFLAGS += -Werror -DEAPOL_TEST
endif
+ifdef CONFIG_HT_OVERRIDES
+L_CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
+ifdef CONFIG_VHT_OVERRIDES
+L_CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -176,6 +194,18 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.c
+endif
+
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
@@ -203,7 +233,7 @@ NEED_SHA1=y
NEED_MD5=y
NEED_RC4=y
else
-L_CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+L_CFLAGS += -DCONFIG_NO_WPA
endif
ifdef CONFIG_IBSS_RSN
@@ -225,6 +255,7 @@ OBJS += src/p2p/p2p_invitation.c
OBJS += src/p2p/p2p_dev_disc.c
OBJS += src/p2p/p2p_group.c
OBJS += src/ap/p2p_hostapd.c
+OBJS += src/utils/bitfield.c
L_CFLAGS += -DCONFIG_P2P
NEED_GAS=y
NEED_OFFCHANNEL=y
@@ -236,16 +267,23 @@ L_CFLAGS += -DCONFIG_P2P_STRICT
endif
endif
+ifdef CONFIG_WIFI_DISPLAY
+L_CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.c
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.c
+L_CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
OBJS += interworking.c
L_CFLAGS += -DCONFIG_INTERWORKING
NEED_GAS=y
endif
-ifdef CONFIG_NO_WPA2
-L_CFLAGS += -DCONFIG_NO_WPA2
-endif
-
include $(LOCAL_PATH)/src/drivers/drivers.mk
ifdef CONFIG_AP
@@ -300,6 +338,17 @@ TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+L_CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_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
+endif
+
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -453,6 +502,13 @@ CONFIG_EAP_SIM_COMMON=y
NEED_AES_CBC=y
endif
+ifdef CONFIG_EAP_PROXY
+L_CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
+include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_AKA_PRIME
# EAP-AKA'
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
@@ -534,11 +590,27 @@ 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_pwd.c
+OBJS_h += src/eap_server/eap_server_pwd.c
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
endif
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+L_CFLAGS += -DEAP_EKE_DYNAMIC
+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
+NEED_DH_GROUPS_ALL=y
+NEED_SHA256=y
+endif
+
ifdef CONFIG_WPS
ifdef CONFIG_WPS2
L_CFLAGS += -DCONFIG_WPS2
@@ -566,25 +638,10 @@ NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
L_CFLAGS += -DCONFIG_WPS_NFC
OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -710,8 +767,15 @@ OBJS += src/ap/ieee802_11_shared.c
OBJS += src/ap/drv_callbacks.c
OBJS += src/ap/ap_drv_ops.c
OBJS += src/ap/beacon.c
+OBJS += src/ap/eap_user_db.c
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+endif
+ifdef CONFIG_WNM
+OBJS += src/ap/wnm_ap.c
endif
ifdef CONFIG_CTRL_IFACE
OBJS += src/ap/ctrl_iface_ap.c
@@ -724,6 +788,9 @@ OBJS += src/eap_server/eap_server_methods.c
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
endif
ifdef NEED_AP_MLME
@@ -731,6 +798,7 @@ OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
OBJS += src/ap/ieee802_11.c
OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_WPS
@@ -738,6 +806,12 @@ L_CFLAGS += -DEAP_SERVER_WSC
OBJS += src/ap/wps_hostapd.c
OBJS += src/eap_server/eap_server_wsc.c
endif
+ifdef CONFIG_INTERWORKING
+OBJS += src/ap/gas_serv.c
+endif
+ifdef CONFIG_HS20
+OBJS += src/ap/hs20.c
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -836,7 +910,11 @@ 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
+NEED_MD5=y
+endif
endif
ifndef CONFIG_TLS
@@ -847,6 +925,11 @@ ifdef CONFIG_TLSV11
L_CFLAGS += -DCONFIG_TLSV11
endif
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
L_CFLAGS += -DEAP_TLS_OPENSSL
@@ -860,6 +943,10 @@ OBJS += src/crypto/fips_prf_openssl.c
endif
LIBS += -lcrypto
LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
@@ -931,6 +1018,9 @@ OBJS += src/tls/pkcs8.c
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -1036,8 +1126,12 @@ AESOBJS += src/crypto/aes-encblock.c
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+L_CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += src/crypto/aes-omac1.c
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += src/crypto/aes-wrap.c
@@ -1057,7 +1151,10 @@ endif
SHA1OBJS =
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
ifdef NEED_FIPS186_2_PRF
@@ -1067,8 +1164,10 @@ endif
ifdef CONFIG_NO_WPA_PASSPHRASE
L_CFLAGS += -DCONFIG_NO_PBKDF2
else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1-pbkdf2.c
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += src/crypto/sha1-tprf.c
endif
@@ -1077,14 +1176,14 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c
endif
endif
-MD5OBJS = src/crypto/md5.c
+MD5OBJS =
+ifndef CONFIG_FIPS
+MD5OBJS += src/crypto/md5.c
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += src/crypto/md5-internal.c
endif
-ifdef CONFIG_FIPS
-MD5OBJS += src/crypto/md5-non-fips.c
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1111,10 +1210,16 @@ endif
SHA256OBJS = # none by default
ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += src/crypto/sha256.c
+endif
+SHA256OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += src/crypto/sha256-internal.c
endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += src/crypto/sha256-tlsprf.c
+endif
OBJS += $(SHA256OBJS)
endif
@@ -1130,6 +1235,10 @@ OBJS += src/crypto/dh_group5.c
endif
endif
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -1154,6 +1263,11 @@ endif
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
endif
@@ -1274,6 +1388,10 @@ L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
endif
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
L_CFLAGS += -DCONFIG_DEBUG_FILE
endif
@@ -1289,6 +1407,7 @@ endif
OBJS += $(SHA1OBJS) $(DESOBJS)
OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
ifdef CONFIG_BGSCAN_SIMPLE
L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1307,8 +1426,36 @@ L_CFLAGS += -DCONFIG_BGSCAN
OBJS += bgscan.c
endif
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+L_CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+L_CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += src/utils/ext_password_test.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += src/utils/ext_password.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
ifdef NEED_GAS
-OBJS += ../src/common/gas.c
+OBJS += src/common/gas.c
OBJS += gas_query.c
L_CFLAGS += -DCONFIG_GAS
NEED_OFFCHANNEL=y
@@ -1346,6 +1493,9 @@ OBJS_priv += src/utils/common.c
OBJS_priv += src/utils/wpa_debug.c
OBJS_priv += src/utils/wpabuf.c
OBJS_priv += wpa_priv.c
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += src/common/ieee802_11_common.c
+endif
ifdef CONFIG_DRIVER_TEST
OBJS_priv += $(SHA1OBJS)
OBJS_priv += $(MD5OBJS)
@@ -1389,14 +1539,12 @@ ifndef LDO
LDO=$(CC)
endif
-ifeq ($(WPA_BUILD_SUPPLICANT),true)
-
########################
include $(CLEAR_VARS)
LOCAL_MODULE := wpa_cli
LOCAL_MODULE_TAGS := debug
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS_c)
LOCAL_C_INCLUDES := $(INCLUDES)
@@ -1411,9 +1559,13 @@ endif
ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
endif
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+ifdef CONFIG_EAP_PROXY
+LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY)
+LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
+endif
ifeq ($(CONFIG_TLS), openssl)
-LOCAL_SHARED_LIBRARIES += libcrypto libssl
+LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
endif
ifdef CONFIG_DRIVER_NL80211
LOCAL_STATIC_LIBRARIES += libnl_2
@@ -1442,7 +1594,6 @@ include $(BUILD_EXECUTABLE)
#
#include $(CLEAR_VARS)
#LOCAL_MODULE := wpa_supplicant.conf
-#LOCAL_MODULE_TAGS := user
#LOCAL_MODULE_CLASS := ETC
#LOCAL_MODULE_PATH := $(local_target_dir)
#LOCAL_SRC_FILES := $(LOCAL_MODULE)
@@ -1450,14 +1601,12 @@ include $(BUILD_EXECUTABLE)
#
########################
-endif # ifeq ($(WPA_BUILD_SUPPLICANT),true)
-
include $(CLEAR_VARS)
LOCAL_MODULE = libwpa_client
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
LOCAL_C_INCLUDES = $(INCLUDES)
-LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_COPY_HEADERS_TO := libwpa_client
LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
include $(BUILD_SHARED_LIBRARY)
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index a849011..e40cf91 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,82 +1,345 @@
ChangeLog for wpa_supplicant
-2012-11-06 - v1.1
- * Fix EAPOL supplicant port authorization with PMKSA caching.
- * Fix EAPOL processing when STA switches between multi-BSSes.
- * Fix EAP-FAST with OpenSSL 1.0.1.
- * EAP-pwd: Increase maximum number of hunting-and-pecking iterations,
- which results in less authentication attempts failing.
- * Set state to DISCONNECTED on AP creation errors. Previously the
- supplicant would stay in SCANNING state forever.
- * Fix REMOVE_NETWORK to not run operations with invalid current_ssid.
- * EAP-SIM peer: Fix AT_COUNTER_TOO_SMALL use.
- * Interworking: Fix PLMN matching with multiple entries to compare all
- entries, not just the first one.
- * Handle long configuration file lines more gracefully.
- * Fix adding extra IEs in sched scan.
- * PMKSA: Set cur_pmksa pointer during initial association.
- * PMKSA: Do not evict the active cache entry when adding new ones.
- * Set state consistently to DISCONNECTED on auth/assoc failures.
- * Fix BSSID enforcement with driver-based BSS selection. Set BSSID and
- channel when the network block has an explicit bssid parameter to
- select which BSS is to be used.
- * wpa_gui: Fix compilation with gcc/g++ 4.7.
- * EAP-AKA'
- - Update to RFC 5448 in the leading characters used in the username.
- This will make EAP-AKA' not interoperate between the earlier draft
- version and the new version.
- - Fix SIM/USIM determination to support EAP-AKA'.
- * dbus:
- - Add global capabilities property.
- - Fix bss_expire_count getter, which was returning the wrong value.
- - P2P: Remove network_object dictionary entry from signal
- GroupStarted.
- - Fix D-Bus build without ctrl_iface.
- * WPS:
- - Fix nonce comparisons to compare all bytes, not just the first byte.
- - Fix NFC password token building with WPS 2.0 to avoid wpabuf
- overflow and application abort if NFC out-of-band mechanism is used
- with WPS 2.0 enabled.
- - Fix cleanup of WPS operations (by clearing them) in WPA_SCANNING
- and WPA_DISCONNECTED states.
- - Fix issue with BSSID filter handling that could cause only a single
- one of the available BSSes to be available or could cause issues
- connecting.
- - Fix overlapping memcpy on WPS interface addition.
- * P2P:
- - Remove channel 14 from supported P2P channels.
- - Fix Provision Discovery retries on delay in off channel
- transmission, to avoid unnecessary retries.
- - Limit maximum number of stored P2P clients (the p2p_client_list
- parameter) to 100.
- - Improve p2p_client_list updates in configuration file, reording
- entries so that the most recently added values are maintained in
- the list if the list gets truncated due to size.
- - Fix Provision Discovery retries during p2p_find by making the
- p2p_find case behave consistently with the limited retry
- behavior used with Provision Discovery retries in the IDLE state.
- - Fix P2P Client Discoverability bit updates so that the bit is only
- updated based on P2P Group Info attribute from a GO.
- - Fix GO Negotiation race condition where both devices may believe
- they are the GO. (Ignore unexpected GO Neg Response if we have
- already sent GO Neg Response.)
- - Deinitialize global P2P context on P2P management interface removal.
- - Wait 100 ms if driver fails to start listen operation. This is a
- workaround for some drivers that may accept the remain-on-channel
- command, but instead of indicating start event for
- remain-on-channel, just indicate that the operation has been
- cancelled immediately.
- - Clone max_sta_num parameter for group interfaces, allowing this
- parameter set in the main config file to apply to dynamically
- created P2P group interfaces.
- - Fix Device ID matching for Probe Request frames, which was checking
- only the first octet of the P2P Device Address.
- - Do not update peer Listen channel based on PD Request Invitation
- Request frames (just on Probe Response frames).
- - Fix p2p_listen to disallow scheduling a new after scan operation
- in the case where a p2p_connect operation is pending.
+2014-02-04 - v2.1
+ * added support for simultaneous authentication of equals (SAE) for
+ stronger password-based authentication with WPA2-Personal
+ * improved P2P negotiation and group formation robustness
+ - avoid unnecessary Dialog Token value changes during retries
+ - avoid more concurrent scanning cases during full group formation
+ sequence
+ - do not use potentially obsolete scan result data from driver
+ cache for peer discovery/updates
+ - avoid undesired re-starting of GO negotiation based on Probe
+ Request frames
+ - increase GO Negotiation and Invitation timeouts to address busy
+ environments and peers that take long time to react to messages,
+ e.g., due to power saving
+ - P2P Device interface type
+ * improved P2P channel selection (use more peer information and allow
+ more local options)
+ * added support for optional per-device PSK assignment by P2P GO
+ (wpa_cli p2p_set per_sta_psk <0/1>)
+ * added P2P_REMOVE_CLIENT for removing a client from P2P groups
+ (including persistent groups); this can be used to securely remove
+ a client from a group if per-device PSKs are used
+ * added more configuration flexibility for allowed P2P GO/client
+ channels (p2p_no_go_freq list and p2p_add_cli_chan=0/1)
+ * added nl80211 functionality
+ - VHT configuration for nl80211
+ - MFP (IEEE 802.11w) information for nl80211 command API
+ - support split wiphy dump
+ - FT (IEEE 802.11r) with driver-based SME
+ - use advertised number of supported concurrent channels
+ - QoS Mapping configuration
+ * improved TDLS negotiation robustness
+ * added more TDLS peer parameters to be configured to the driver
+ * optimized connection time by allowing recently received scan results
+ to be used instead of having to run through a new scan
+ * fixed ctrl_iface BSS command iteration with RANGE argument and no
+ exact matches; also fixed argument parsing for some cases with
+ multiple arguments
+ * added 'SCAN TYPE=ONLY' ctrl_iface command to request manual scan
+ without executing roaming/network re-selection on scan results
+ * added Session-Id derivation for EAP peer methods
+ * added fully automated regression testing with mac80211_hwsim
+ * changed configuration parser to reject invalid integer values
+ * allow AP/Enrollee to be specified with BSSID instead of UUID for
+ WPS ER operations
+ * disable network block temporarily on repeated connection failures
+ * changed the default driver interface from wext to nl80211 if both are
+ included in the build
+ * remove duplicate networks if WPS provisioning is run multiple times
+ * remove duplicate networks when Interworking network selection uses the
+ same network
+ * added global freq_list configuration to allow scan frequencies to be
+ limited for all cases instead of just for a specific network block
+ * added support for BSS Transition Management
+ * added option to use "IFNAME=<ifname> " prefix to use the global
+ control interface connection to perform per-interface commands;
+ similarly, allow global control interface to be used as a monitor
+ interface to receive events from all interfaces
+ * fixed OKC-based PMKSA cache entry clearing
+ * fixed TKIP group key configuration with FT
+ * added support for using OCSP stapling to validate server certificate
+ (ocsp=1 as optional and ocsp=2 as mandatory)
+ * added EAP-EKE peer
+ * added peer restart detection for IBSS RSN
+ * added domain_suffix_match (and domain_suffix_match2 for Phase 2
+ EAP-TLS) to specify additional constraint for the server certificate
+ domain name
+ * added support for external SIM/USIM processing in EAP-SIM, EAP-AKA,
+ and EAP-AKA' (CTRL-REQ-SIM and CTRL-RSP-SIM commands over control
+ interface)
+ * added global bgscan configuration option as a default for all network
+ blocks that do not specify their own bgscan parameters
+ * added D-Bus methods for TDLS
+ * added more control to scan requests
+ - "SCAN freq=<freq list>" can be used to specify which channels are
+ scanned (comma-separated frequency ranges in MHz)
+ - "SCAN passive=1" can be used to request a passive scan (no Probe
+ Request frames are sent)
+ - "SCAN use_id" can be used to request a scan id to be returned and
+ included in event messages related to this specific scan operation
+ - "SCAN only_new=1" can be used to request the driver/cfg80211 to
+ report only BSS entries that have been updated during this scan
+ round
+ - these optional arguments to the SCAN command can be combined with
+ each other
+ * modified behavior on externally triggered scans
+ - avoid concurrent operations requiring full control of the radio when
+ an externally triggered scan is detected
+ - do not use results for internal roaming decision
+ * added a new cred block parameter 'temporary' to allow credential
+ blocks to be stored separately even if wpa_supplicant configuration
+ file is used to maintain other network information
+ * added "radio work" framework to schedule exclusive radio operations
+ for off-channel functionality
+ - reduce issues with concurrent operations that try to control which
+ channel is used
+ - allow external programs to request exclusive radio control in a way
+ that avoids conflicts with wpa_supplicant
+ * added support for using Protected Dual of Public Action frames for
+ GAS/ANQP exchanges when associated with PMF
+ * added support for WPS+NFC updates and P2P+NFC
+ - improved protocol for WPS
+ - P2P group formation/join based on NFC connection handover
+ - new IPv4 address assignment for P2P groups (ip_addr_* configuration
+ parameters on the GO) to replace DHCP
+ - option to fetch and report alternative carrier records for external
+ NFC operations
+ * various bug fixes
+
+2013-01-12 - v2.0
+ * removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
+ * removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
+ hostap, madwifi (hostap and madwifi remain available for hostapd;
+ their wpa_supplicant functionality is obsoleted by wext)
+ * improved debug logging (human readable event names, interface name
+ included in more entries)
+ * changed AP mode behavior to enable WPS only for open and
+ WPA/WPA2-Personal configuration
+ * improved P2P concurrency operations
+ - better coordination of concurrent scan and P2P search operations
+ - avoid concurrent remain-on-channel operation requests by canceling
+ previous operations prior to starting a new one
+ - reject operations that would require multi-channel concurrency if
+ the driver does not support it
+ - add parameter to select whether STA or P2P connection is preferred
+ if the driver cannot support both at the same time
+ - allow driver to indicate channel changes
+ - added optional delay=<search delay in milliseconds> parameter for
+ p2p_find to avoid taking all radio resources
+ - use 500 ms p2p_find search delay by default during concurrent
+ operations
+ - allow all channels in GO Negotiation if the driver supports
+ multi-channel concurrency
+ * added number of small changes to make it easier for static analyzers
+ to understand the implementation
+ * fixed number of small bugs (see git logs for more details)
+ * nl80211: number of updates to use new cfg80211/nl80211 functionality
+ - replace monitor interface with nl80211 commands for AP mode
+ - additional information for driver-based AP SME
+ - STA entry authorization in RSN IBSS
+ * EAP-pwd:
+ - fixed KDF for group 21 and zero-padding
+ - added support for fragmentation
+ - increased maximum number of hunting-and-pecking iterations
+ * avoid excessive Probe Response retries for broadcast Probe Request
+ frames (only with drivers using wpa_supplicant AP mode SME/MLME)
+ * added "GET country" ctrl_iface command
+ * do not save an invalid network block in wpa_supplicant.conf to avoid
+ problems reading the file on next start
+ * send STA connected/disconnected ctrl_iface events to both the P2P
+ group and parent interfaces
+ * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+ * added "SET pno <1/0>" ctrl_iface command to start/stop preferred
+ network offload with sched_scan driver command
+ * merged in number of changes from Android repository for P2P, nl80211,
+ and build parameters
+ * changed P2P GO mode configuration to use driver capabilities to
+ automatically enable HT operations when supported
+ * added "wpa_cli status wps" command to fetch WPA2-Personal passhrase
+ for WPS use cases in AP mode
+ * EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM
+ behavior
+ * improved reassociation behavior in cases where association is rejected
+ or when an AP disconnects us to handle common load balancing
+ mechanisms
+ - try to avoid extra scans when the needed information is available
+ * added optional "join" argument for p2p_prov_disc ctrl_iface command
+ * added group ifname to P2P-PROV-DISC-* events
+ * added P2P Device Address to AP-STA-DISCONNECTED event and use
+ p2p_dev_addr parameter name with AP-STA-CONNECTED
+ * added workarounds for WPS PBC overlap detection for some P2P use cases
+ where deployed stations work incorrectly
+ * optimize WPS connection speed by disconnecting prior to WPS scan and
+ by using single channel scans when AP channel is known
+ * PCSC and SIM/USIM improvements:
+ - accept 0x67 (Wrong length) as a response to READ RECORD to fix
+ issues with some USIM cards
+ - try to read MNC length from SIM/USIM
+ - build realm according to 3GPP TS 23.003 with identity from the SIM
+ - allow T1 protocol to be enabled
+ * added more WPS and P2P information available through D-Bus
+ * improve P2P negotiation robustness
+ - extra waits to get ACK frames through
+ - longer timeouts for cases where deployed devices have been
+ identified have issues meeting the specification requirements
+ - more retries for some P2P frames
+ - handle race conditions in GO Negotiation start by both devices
+ - ignore unexpected GO Negotiation Response frame
+ * added support for libnl 3.2 and newer
+ * added P2P persistent group info to P2P_PEER data
+ * maintain a list of P2P Clients for persistent group on GO
+ * AP: increased initial group key handshake retransmit timeout to 500 ms
+ * added optional dev_id parameter for p2p_find
+ * added P2P-FIND-STOPPED ctrl_iface event
+ * fixed issues in WPA/RSN element validation when roaming with ap_scan=1
+ and driver-based BSS selection
+ * do not expire P2P peer entries while connected with the peer in a
+ group
+ * fixed WSC element inclusion in cases where P2P is disabled
+ * AP: added a WPS workaround for mixed mode AP Settings with Windows 7
+ * EAP-SIM: fixed AT_COUNTER_TOO_SMALL use
+ * EAP-SIM/AKA: append realm to pseudonym identity
+ * EAP-SIM/AKA: store pseudonym identity in network configuration to
+ allow it to persist over multiple EAP sessions and wpa_supplicant
+ restarts
+ * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+ breaks interoperability with older versions
+ * added support for WFA Hotspot 2.0
+ - GAS/ANQP to fetch network information
+ - credential configuration and automatic network selections based on
+ credential match with ANQP information
+ * limited PMKSA cache entries to be used only with the network context
+ that was used to create them
+ * improved PMKSA cache expiration to avoid unnecessary disconnections
+ * adjusted bgscan_simple fast-scan backoff to avoid too frequent
+ background scans
+ * removed ctrl_iface event on P2P PD Response in join-group case
+ * added option to fetch BSS table entry based on P2P Device Address
+ ("BSS p2p_dev_addr=<P2P Device Address>")
+ * added BSS entry age to ctrl_iface BSS command output
+ * added optional MASK=0xH option for ctrl_iface BSS command to select
+ which fields are included in the response
+ * added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to
+ fetch information about several BSSes in one call
+ * simplified licensing terms by selecting the BSD license as the only
+ alternative
+ * added "P2P_SET disallow_freq <freq list>" ctrl_iface command to
+ disable channels from P2P use
+ * added p2p_pref_chan configuration parameter to allow preferred P2P
+ channels to be specified
+ * added support for advertising immediate availability of a WPS
+ credential for P2P use cases
+ * optimized scan operations for P2P use cases (use single channel scan
+ for a specific SSID when possible)
+ * EAP-TTLS: fixed peer challenge generation for MSCHAPv2
+ * SME: do not use reassociation after explicit disconnection request
+ (local or a notification from an AP)
+ * added support for sending debug info to Linux tracing (-T on command
+ line)
+ * added support for using Deauthentication reason code 3 as an
+ indication of P2P group termination
+ * added wps_vendor_ext_m1 configuration parameter to allow vendor
+ specific attributes to be added to WPS M1
+ * started using separate TLS library context for tunneled TLS
+ (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA
+ certificate configuration between Phase 1 and Phase 2
+ * added optional "auto" parameter for p2p_connect to request automatic
+ GO Negotiation vs. join-a-group selection
+ * added disabled_scan_offload parameter to disable automatic scan
+ offloading (sched_scan)
+ * added optional persistent=<network id> parameter for p2p_connect to
+ allow forcing of a specific SSID/passphrase for GO Negotiation
+ * added support for OBSS scan requests and 20/40 BSS coexistence reports
+ * reject PD Request for unknown group
+ * removed scripts and notes related to Windows binary releases (which
+ have not been used starting from 1.x)
+ * added initial support for WNM operations
+ - Keep-alive based on BSS max idle period
+ - WNM-Sleep Mode
+ - minimal BSS Transition Management processing
+ * added autoscan module to control scanning behavior while not connected
+ - autoscan_periodic and autoscan_exponential modules
+ * added new WPS NFC ctrl_iface mechanism
+ - added initial support NFC connection handover
+ - removed obsoleted WPS_OOB command (including support for deprecated
+ UFD config_method)
+ * added optional framework for external password storage ("ext:<name>")
+ * wpa_cli: added optional support for controlling wpa_supplicant
+ remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes
+ * wpa_cli: extended tab completion to more commands
+ * changed SSID output to use printf-escaped strings instead of masking
+ of non-ASCII characters
+ - SSID can now be configured in the same format: ssid=P"abc\x00test"
+ * removed default ACM=1 from AC_VO and AC_VI
+ * added optional "ht40" argument for P2P ctrl_iface commands to allow
+ 40 MHz channels to be requested on the 5 GHz band
+ * added optional parameters for p2p_invite command to specify channel
+ when reinvoking a persistent group as the GO
+ * improved FIPS mode builds with OpenSSL
+ - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the
+ OpenSSL FIPS object module
+ - replace low level OpenSSL AES API calls to use EVP
+ - use OpenSSL keying material exporter when possible
+ - do not export TLS keys in FIPS mode
+ - remove MD5 from CONFIG_FIPS=y builds
+ - use OpenSSL function for PKBDF2 passphrase-to-PSK
+ - use OpenSSL HMAC implementation
+ - mix RAND_bytes() output into random_get_bytes() to force OpenSSL
+ DRBG to be used in FIPS mode
+ - use OpenSSL CMAC implementation
+ * added mechanism to disable TLS Session Ticket extension
+ - a workaround for servers that do not support TLS extensions that
+ was enabled by default in recent OpenSSL versions
+ - tls_disable_session_ticket=1
+ - automatically disable TLS Session Ticket extension by default when
+ using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST)
+ * changed VENDOR-TEST EAP method to use proper private enterprise number
+ (this will not interoperate with older versions)
+ * disable network block temporarily on authentication failures
+ * improved WPS AP selection during WPS PIN iteration
+ * added support for configuring GCMP cipher for IEEE 802.11ad
+ * added support for Wi-Fi Display extensions
+ - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements
+ - SET wifi_display <0/1> to disable/enable WFD support
+ - WFD service discovery
+ - an external program is needed to manage the audio/video streaming
+ and codecs
+ * optimized scan result use for network selection
+ - use the internal BSS table instead of raw scan results
+ - allow unnecessary scans to be skipped if fresh information is
+ available (e.g., after GAS/ANQP round for Interworking)
+ * added support for 256-bit AES with internal TLS implementation
+ * allow peer to propose channel in P2P invitation process for a
+ persistent group
+ * added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed
+ from network selection
+ * re-enable the networks disabled during WPS operations
+ * allow P2P functionality to be disabled per interface (p2p_disabled=1)
+ * added secondary device types into P2P_PEER output
+ * added an option to disable use of a separate P2P group interface
+ (p2p_no_group_iface=1)
+ * fixed P2P Bonjour SD to match entries with both compressed and not
+ compressed domain name format and support multiple Bonjour PTR matches
+ for the same key
+ * use deauthentication instead of disassociation for all disconnection
+ operations; this removes the now unused disassociate() wpa_driver_ops
+ callback
+ * optimized PSK generation on P2P GO by caching results to avoid
+ multiple PBKDF2 operations
+ * added okc=1 global configuration parameter to allow OKC to be enabled
+ by default for all network blocks
+ * added a workaround for WPS PBC session overlap detection to avoid
+ interop issues with deployed station implementations that do not
+ remove active PBC indication from Probe Request frames properly
+ * added basic support for 60 GHz band
+ * extend EAPOL frames processing workaround for roaming cases
+ (postpone processing of unexpected EAPOL frame until association
+ event to handle reordered events)
-2012-04-18 - v1.0
+2012-05-10 - v1.0
* bsd: Add support for setting HT values in IFM_MMASK.
* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
This allows the driver to use PS buffering of Deauthentication and
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 22df8a0..d1e11a3 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -10,11 +10,17 @@ export LIBDIR ?= /usr/local/lib/
export BINDIR ?= /usr/local/sbin/
PKG_CONFIG ?= pkg-config
-CFLAGS += -I../src
-CFLAGS += -I../src/utils
+CFLAGS += -I$(abspath ../src)
+CFLAGS += -I$(abspath ../src/utils)
-include .config
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+CONFIG_TDLS_TESTING=y
+endif
+
BINALL=wpa_supplicant wpa_cli
ifndef CONFIG_NO_WPA_PASSPHRASE
@@ -55,6 +61,11 @@ $(DESTDIR)$(BINDIR)/%: %
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
$(MAKE) -C ../src install
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.o
OBJS += notify.o
OBJS += bss.o
@@ -108,11 +119,37 @@ endif
OBJS += ../src/utils/$(CONFIG_ELOOP).o
OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_p += -lrt
+endif
+
+ifdef CONFIG_ELOOP_POLL
+CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
+ifdef CONFIG_CODE_COVERAGE
+CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+LIBS += -lgcov
+LIBS_c += -lgcov
+LIBS_p += -lgcov
+endif
+
+ifdef CONFIG_HT_OVERRIDES
+CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
+ifdef CONFIG_VHT_OVERRIDES
+CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -159,6 +196,18 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.o
+endif
+
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
@@ -186,7 +235,7 @@ NEED_SHA1=y
NEED_MD5=y
NEED_RC4=y
else
-CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA
endif
ifdef CONFIG_IBSS_RSN
@@ -208,6 +257,7 @@ OBJS += ../src/p2p/p2p_invitation.o
OBJS += ../src/p2p/p2p_dev_disc.o
OBJS += ../src/p2p/p2p_group.o
OBJS += ../src/ap/p2p_hostapd.o
+OBJS += ../src/utils/bitfield.o
CFLAGS += -DCONFIG_P2P
NEED_GAS=y
NEED_OFFCHANNEL=y
@@ -219,16 +269,23 @@ CFLAGS += -DCONFIG_P2P_STRICT
endif
endif
+ifdef CONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.o
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.o
+CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
OBJS += interworking.o
CFLAGS += -DCONFIG_INTERWORKING
NEED_GAS=y
endif
-ifdef CONFIG_NO_WPA2
-CFLAGS += -DCONFIG_NO_WPA2
-endif
-
include ../src/drivers/drivers.mak
ifdef CONFIG_AP
OBJS_d += $(DRV_BOTH_OBJS)
@@ -282,6 +339,17 @@ TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+OBJS_h += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -435,6 +503,13 @@ CONFIG_EAP_SIM_COMMON=y
NEED_AES_CBC=y
endif
+ifdef CONFIG_EAP_PROXY
+CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o
+include eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_AKA_PRIME
# EAP-AKA'
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
@@ -516,8 +591,24 @@ 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_pwd.o
+OBJS_h += ../src/eap_server/eap_server_pwd.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+CFLAGS += -DEAP_EKE_DYNAMIC
+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
+NEED_DH_GROUPS_ALL=y
NEED_SHA256=y
endif
@@ -548,25 +639,10 @@ NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
CFLAGS += -DCONFIG_WPS_NFC
OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -692,8 +768,15 @@ OBJS += ../src/ap/ieee802_11_shared.o
OBJS += ../src/ap/drv_callbacks.o
OBJS += ../src/ap/ap_drv_ops.o
OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/eap_user_db.o
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+endif
+ifdef CONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
endif
ifdef CONFIG_CTRL_IFACE
OBJS += ../src/ap/ctrl_iface_ap.o
@@ -706,6 +789,9 @@ OBJS += ../src/eap_server/eap_server_methods.o
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
endif
ifdef NEED_AP_MLME
@@ -713,6 +799,7 @@ OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
OBJS += ../src/ap/ieee802_11.o
OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_WPS
@@ -720,6 +807,12 @@ CFLAGS += -DEAP_SERVER_WSC
OBJS += ../src/ap/wps_hostapd.o
OBJS += ../src/eap_server/eap_server_wsc.o
endif
+ifdef CONFIG_INTERWORKING
+OBJS += ../src/ap/gas_serv.o
+endif
+ifdef CONFIG_HS20
+OBJS += ../src/ap/hs20.o
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -818,7 +911,11 @@ 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
+NEED_MD5=y
+endif
endif
ifndef CONFIG_TLS
@@ -829,6 +926,11 @@ ifdef CONFIG_TLSV11
CFLAGS += -DCONFIG_TLSV11
endif
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL
@@ -842,6 +944,10 @@ OBJS += ../src/crypto/fips_prf_openssl.o
endif
LIBS += -lcrypto
LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
@@ -913,6 +1019,9 @@ OBJS += ../src/tls/pkcs8.o
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -1018,8 +1127,12 @@ AESOBJS += ../src/crypto/aes-encblock.o
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += ../src/crypto/aes-omac1.o
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-wrap.o
@@ -1038,7 +1151,10 @@ OBJS += $(AESOBJS)
endif
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
@@ -1048,8 +1164,10 @@ endif
ifdef CONFIG_NO_WPA_PASSPHRASE
CFLAGS += -DCONFIG_NO_PBKDF2
else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -1058,14 +1176,13 @@ SHA1OBJS += ../src/crypto/sha1-tlsprf.o
endif
endif
-MD5OBJS = ../src/crypto/md5.o
+ifndef CONFIG_FIPS
+MD5OBJS += ../src/crypto/md5.o
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += ../src/crypto/md5-internal.o
endif
-ifdef CONFIG_FIPS
-MD5OBJS += ../src/crypto/md5-non-fips.o
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1092,10 +1209,16 @@ endif
SHA256OBJS = # none by default
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += ../src/crypto/sha256.o
+endif
+SHA256OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += ../src/crypto/sha256-internal.o
endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+endif
OBJS += $(SHA256OBJS)
endif
@@ -1111,6 +1234,10 @@ OBJS += ../src/crypto/dh_group5.o
endif
endif
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -1135,6 +1262,11 @@ endif
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
endif
@@ -1251,6 +1383,10 @@ CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
endif
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
CFLAGS += -DCONFIG_DEBUG_FILE
endif
@@ -1261,11 +1397,15 @@ endif
ifdef CONFIG_FIPS
CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
endif
OBJS += $(SHA1OBJS) $(DESOBJS)
OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
ifdef CONFIG_BGSCAN_SIMPLE
CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1284,6 +1424,34 @@ CFLAGS += -DCONFIG_BGSCAN
OBJS += bgscan.o
endif
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.o
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
ifdef NEED_GAS
OBJS += ../src/common/gas.o
OBJS += gas_query.o
@@ -1297,6 +1465,7 @@ CFLAGS += -DCONFIG_OFFCHANNEL
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
@@ -1312,6 +1481,10 @@ ifndef CONFIG_AP
OBJS_t += ../src/utils/ip_addr.o
endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
+
+OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
+OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o
+
OBJS += $(CONFIG_MAIN).o
ifdef CONFIG_PRIVSEP
@@ -1390,15 +1563,17 @@ wpa_priv: $(BCHECK) $(OBJS_priv)
$(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
@$(E) " LD " $@
-wpa_supplicant: .config $(BCHECK) $(OBJS) $(EXTRA_progs)
+$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
+
+wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
@$(E) " LD " $@
-eapol_test: .config $(OBJS_t)
+eapol_test: $(OBJS_t)
$(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
@$(E) " LD " $@
-preauth_test: .config $(OBJS_t2)
+preauth_test: $(OBJS_t2)
$(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
@$(E) " LD " $@
@@ -1418,6 +1593,10 @@ test_wpa: $(OBJS_wpa) $(OBJS_h)
$(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
@$(E) " LD " $@
+nfc_pw_token: $(OBJS_nfc)
+ $(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
+ @$(E) " LD " $@
+
win_if_list: win_if_list.c
$(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
@$(E) " LD " $@
@@ -1442,17 +1621,30 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_com
$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-Deap_peer_ikev2_register=eap_peer_method_dynamic_init
+eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c
+ $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_eke_register=eap_peer_method_dynamic_init
+
%.so: %.c
$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
+ifdef CONFIG_CODE_COVERAGE
+%.o: %.c
+ @$(E) " CC " $<
+ $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
+else
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
+endif
%.service: %.service.in
sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+%@.service: %.service.arg.in
+ sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
wpa_supplicant.exe: wpa_supplicant
mv -f $< $@
wpa_cli.exe: wpa_cli
@@ -1469,11 +1661,8 @@ WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
windows-bin: $(WINALL)
$(STRIP) $(WINALL)
-wpa_gui/Makefile:
- qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro
-
-wpa_gui: wpa_gui/Makefile
- $(MAKE) -C wpa_gui
+wpa_gui:
+ @echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement"
wpa_gui-qt4/Makefile:
qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro
@@ -1495,10 +1684,23 @@ test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
tests: test-eap_sim_common
+FIPSDIR=/usr/local/ssl/fips-2.0
+FIPSLD=$(FIPSDIR)/bin/fipsld
+fips:
+ $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
+
+lcov-html: wpa_supplicant.gcda
+ lcov -c -d .. > lcov.info
+ genhtml lcov.info --output-directory lcov-html
+
clean:
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
- rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+ rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
rm -f wpa_priv
+ rm -f nfc_pw_token
+ rm -f lcov.info
+ rm -rf lcov-html
-include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index f324192..7f88cd6 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,37 +1,22 @@
WPA Supplicant
==============
-Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
License
-------
-GPL v2:
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-(this copy of the license is in COPYING file)
-
-
-Alternatively, this software may be distributed, used, and modified
-under the terms of BSD license:
+This software may be distributed, used, and modified under the terms of
+BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -130,46 +115,15 @@ Current hardware/software requirements:
- NetBSD-current
- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
- drivers:
- Linux drivers that support WPA/WPA2 configuration with the generic
- Linux wireless extensions (WE-18 or newer). Even though there are
+ Linux drivers that support cfg80211/nl80211. Even though there are
number of driver specific interface included in wpa_supplicant, please
- note that Linux drivers are moving to use generic wireless extensions
- and driver_wext (-Dwext on wpa_supplicant command line) should be the
- default option to start with before falling back to driver specific
- interface.
-
- Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
- (http://hostap.epitest.fi/)
- Driver need to be set in Managed mode ('iwconfig wlan0 mode managed').
- Please note that station firmware version needs to be 1.7.0 or newer
- to work in WPA mode.
-
- Linuxant DriverLoader (http://www.linuxant.com/driverloader/)
- with Windows NDIS driver for your wlan card supporting WPA.
-
- madwifi driver for cards based on Atheros chip set (ar521x)
- (http://sourceforge.net/projects/madwifi/)
- Please note that you will need to modify the wpa_supplicant .config
- file to use the correct path for the madwifi driver root directory
- (CFLAGS += -I../madwifi/wpa line in example defconfig).
-
- Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
- Windows NDIS driver.
-
- Broadcom wl.o driver (old version only)
- This is a generic Linux driver for Broadcom IEEE 802.11a/g cards.
- However, it is proprietary driver that is not publicly available
- except for couple of exceptions, mainly Broadcom-based APs/wireless
- routers that use Linux. The driver binary can be downloaded, e.g.,
- from Linksys support site (http://www.linksys.com/support/gpl.asp)
- for Linksys WRT54G. The GPL tarball includes cross-compiler and
- the needed header file, wlioctl.h, for compiling wpa_supplicant.
- This driver support in wpa_supplicant is expected to work also with
- other devices based on Broadcom driver (assuming the driver includes
- client mode support). Please note that the newer Broadcom driver
- ("hybrid Linux driver") supports Linux wireless extensions and does
- not need (or even work) with the specific driver wrapper. Use -Dwext
- with that driver.
+ note that Linux drivers are moving to use generic wireless configuration
+ interface driver_nl80211 (-Dnl80211 on wpa_supplicant command line)
+ should be the default option to start with before falling back to driver
+ specific interface.
+
+ Linux drivers that support WPA/WPA2 configuration with the generic
+ Linux wireless extensions (WE-18 or newer). Obsoleted by nl80211.
In theory, any driver that supports Linux wireless extensions can be
used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
@@ -347,7 +301,7 @@ and a list of available options and additional notes.
The build time configuration can be used to select only the needed
features and limit the binary size and requirements for external
libraries. The main configuration parts are the selection of which
-driver interfaces (e.g., hostap, madwifi, ..) and which authentication
+driver interfaces (e.g., nl80211, wext, ..) and which authentication
methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
Following build time configuration options are used to control IEEE
@@ -382,21 +336,16 @@ CONFIG_PCSC=y
Following options can be added to .config to select which driver
interfaces are included.
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_MADWIFI=y
+CONFIG_DRIVER_NL80211=y
CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_RALINK=y
-CONFIG_DRIVER_BROADCOM=y
CONFIG_DRIVER_BSD=y
CONFIG_DRIVER_NDIS=y
-Following example includes all features and driver interfaces that are
-included in the wpa_supplicant package:
+Following example includes some more features and driver interfaces that
+are included in the wpa_supplicant package:
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_MADWIFI=y
+CONFIG_DRIVER_NL80211=y
CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_BROADCOM=y
CONFIG_DRIVER_BSD=y
CONFIG_DRIVER_NDIS=y
CONFIG_IEEE8021X_EAPOL=y
@@ -461,6 +410,7 @@ Command line options
usage:
wpa_supplicant [-BddfhKLqqtuvwW] [-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>] \
[-p<driver_param>] [-b<br_ifname>] ...]
@@ -475,10 +425,11 @@ options:
-D = driver name (can be multiple drivers: nl80211,wext)
-f = Log output to default log location (normally /tmp)
-g = global ctrl_interface
+ -G = global ctrl_interface group
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
-h = show this help text
- -L = show license (GPL and BSD)
+ -L = show license (BSD)
-p = driver parameters
-P = PID file
-q = decrease debugging verbosity (-qq even less)
@@ -489,12 +440,8 @@ options:
-N = start describing new interface
drivers:
- hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
- (this can also be used with Linuxant DriverLoader)
- madwifi = MADWIFI 802.11 support (Atheros, etc.) (deprecated; use wext)
+ nl80211 = Linux nl80211/cfg80211
wext = Linux wireless extensions (generic)
- ralink = Ralink Client driver
- broadcom = Broadcom wl.o driver
wired = wpa_supplicant wired Ethernet driver
roboswitch = wpa_supplicant Broadcom switch driver
bsd = BSD 802.11 support (Atheros, etc.)
@@ -527,15 +474,15 @@ separated with -N argument. As an example, following command would
start wpa_supplicant for two interfaces:
wpa_supplicant \
- -c wpa1.conf -i wlan0 -D hostap -N \
- -c wpa2.conf -i ath0 -D madwifi
+ -c wpa1.conf -i wlan0 -D nl80211 -N \
+ -c wpa2.conf -i wlan1 -D wext
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:
-wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0
+wpa_supplicant -cw.conf -Dnl80211 -iwlan0 -bbr0
Configuration file
@@ -927,10 +874,10 @@ network (SSID):
# Start wpa_supplicant in the background
wpa_supplicant -g/var/run/wpa_supplicant-global -B
-# Add a new interface (wlan0, no configuration file, driver=wext, and
+# Add a new interface (wlan0, no configuration file, driver=nl80211, and
# enable control interface)
wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
- "" wext /var/run/wpa_supplicant
+ "" nl80211 /var/run/wpa_supplicant
# Configure a network using the newly added network interface:
wpa_cli -iwlan0 add_network
@@ -991,7 +938,7 @@ Example configuration:
chmod 0750 /var/run/wpa_priv
- start wpa_priv as root (e.g., from system startup scripts) with the
enabled interfaces configured on the command line:
- wpa_priv -B -P /var/run/wpa_priv.pid wext:ath0
+ wpa_priv -B -P /var/run/wpa_priv.pid nl80211:wlan0
- run wpa_supplicant as non-root with a user that is in wpapriv group:
wpa_supplicant -i ath0 -c wpa_supplicant.conf
@@ -1002,3 +949,105 @@ can be started when an interface is added (hotplug/udev/etc. scripts).
wpa_priv can control multiple interface with one process, but it is
also possible to run multiple wpa_priv processes at the same time, if
desired.
+
+
+Linux capabilities instead of privileged process
+------------------------------------------------
+
+wpa_supplicant performs operations that need special permissions, e.g.,
+to control the network connection. Traditionally this has been achieved
+by running wpa_supplicant as a privileged process with effective user id
+0 (root). Linux capabilities can be used to provide restricted set of
+capabilities to match the functions needed by wpa_supplicant. The
+minimum set of capabilities needed for the operations is CAP_NET_ADMIN
+and CAP_NET_RAW.
+
+setcap(8) can be used to set file capabilities. For example:
+
+sudo setcap cap_net_raw,cap_net_admin+ep wpa_supplicant
+
+Please note that this would give anyone being able to run that
+wpa_supplicant binary access to the additional capabilities. This can
+further be limited by file owner/group and mode bits. For example:
+
+sudo chown wpas wpa_supplicant
+sudo chmod 0100 wpa_supplicant
+
+This combination of setcap, chown, and chmod commands would allow wpas
+user to execute wpa_supplicant with additional network admin/raw
+capabilities.
+
+Common way style of creating a control interface socket in
+/var/run/wpa_supplicant could not be done by this user, but this
+directory could be created before starting the wpa_supplicant and set to
+suitable mode to allow wpa_supplicant to create sockets
+there. Alternatively, other directory or abstract socket namespace could
+be used for the control interface.
+
+
+External requests for radio control
+-----------------------------------
+
+External programs can request wpa_supplicant to not start offchannel
+operations during other tasks that may need exclusive control of the
+radio. The RADIO_WORK control interface command can be used for this.
+
+"RADIO_WORK add <name> [freq=<MHz>] [timeout=<seconds>]" command can be
+used to reserve a slot for radio access. If freq is specified, other
+radio work items on the same channel may be completed in
+parallel. Otherwise, all other radio work items are blocked during
+execution. Timeout is set to 10 seconds by default to avoid blocking
+wpa_supplicant operations for excessive time. If a longer (or shorter)
+safety timeout is needed, that can be specified with the optional
+timeout parameter. This command returns an identifier for the radio work
+item.
+
+Once the radio work item has been started, "EXT-RADIO-WORK-START <id>"
+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
+happened. "RADIO_WORK done <id>" can also be used to cancel items that
+have not yet been started.
+
+For example, in wpa_cli interactive mode:
+
+> radio_work add test
+1
+<3>EXT-RADIO-WORK-START 1
+> radio_work show
+ext:test@wlan0:0:1:2.487797
+> radio_work done 1
+OK
+> radio_work show
+
+
+> radio_work done 3
+OK
+> radio_work show
+ext:test freq=2412 timeout=30@wlan0:2412:1:28.583483
+<3>EXT-RADIO-WORK-TIMEOUT 2
+
+
+> radio_work add test2 freq=2412 timeout=60
+5
+<3>EXT-RADIO-WORK-START 5
+> radio_work add test3
+6
+> radio_work add test4
+7
+> radio_work show
+ext:test2 freq=2412 timeout=60@wlan0:2412:1:9.751844
+ext:test3@wlan0:0:0:5.071812
+ext:test4@wlan0:0:0:3.143870
+> radio_work done 6
+OK
+> radio_work show
+ext:test2 freq=2412 timeout=60@wlan0:2412:1:16.287869
+ext:test4@wlan0:0:0:9.679895
+> radio_work done 5
+OK
+<3>EXT-RADIO-WORK-START 7
+<3>EXT-RADIO-WORK-TIMEOUT 7
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
new file mode 100644
index 0000000..ad29ef7
--- /dev/null
+++ b/wpa_supplicant/README-HS20
@@ -0,0 +1,507 @@
+wpa_supplicant and Hotspot 2.0
+==============================
+
+This document describe how the IEEE 802.11u Interworking and Wi-Fi
+Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be
+configured and how an external component on the client e.g., management
+GUI or Wi-Fi framework) is used to manage this functionality.
+
+
+Introduction to Wi-Fi Hotspot 2.0
+---------------------------------
+
+Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used
+in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about
+this is available in this white paper:
+
+http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless
+
+The Hotspot 2.0 specification is also available from WFA:
+https://www.wi-fi.org/knowledge-center/published-specifications
+
+The core Interworking functionality (network selection, GAS/ANQP) were
+standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std
+802.11-2012.
+
+
+wpa_supplicant network selection
+--------------------------------
+
+Interworking support added option for configuring credentials that can
+work with multiple networks as an alternative to configuration of
+network blocks (e.g., per-SSID parameters). When requested to perform
+network selection, wpa_supplicant picks the highest priority enabled
+network block or credential. If a credential is picked (based on ANQP
+information from APs), a temporary network block is created
+automatically for the matching network. This temporary network block is
+used similarly to the network blocks that can be configured by the user,
+but it is not stored into the configuration file and is meant to be used
+only for temporary period of time since a new one can be created
+whenever needed based on ANQP information and the credential.
+
+By default, wpa_supplicant is not using automatic network selection
+unless requested explicitly with the interworking_select command. This
+can be changed with the auto_interworking=1 parameter to perform network
+selection automatically whenever trying to find a network for connection
+and none of the enabled network blocks match with the scan results. This
+case works similarly to "interworking_select auto", i.e., wpa_supplicant
+will internally determine which network or credential is going to be
+used based on configured priorities, scan results, and ANQP information.
+
+
+wpa_supplicant configuration
+----------------------------
+
+Interworking and Hotspot 2.0 functionality are optional components that
+need to be enabled in the wpa_supplicant build configuration
+(.config). This is done by adding following parameters into that file:
+
+CONFIG_INTERWORKING=y
+CONFIG_HS20=y
+
+It should be noted that this functionality requires a driver that
+supports GAS/ANQP operations. This uses the same design as P2P, i.e.,
+Action frame processing and building in user space within
+wpa_supplicant. The Linux nl80211 driver interface provides the needed
+functionality for this.
+
+
+There are number of run-time configuration parameters (e.g., in
+wpa_supplicant.conf when using the configuration file) that can be used
+to control Hotspot 2.0 operations.
+
+# Enable Interworking
+interworking=1
+
+# Enable Hotspot 2.0
+hs20=1
+
+# Parameters for controlling scanning
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+#hessid=00:11:22:33:44:55
+
+# Access Network Type
+# When Interworking is enabled, scans can be limited to APs that advertise the
+# specified Access Network Type (0..15; with 15 indicating wildcard match).
+# This value controls the Access Network Type value in Probe Request frames.
+#access_network_type=15
+
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
+
+
+Credentials can be pre-configured for automatic network selection:
+
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# temporary: Whether this credential is temporary and not to be saved
+#
+# priority: Priority group
+# By default, all networks and credentials get the same priority group
+# (0). This field can be used to give higher priority for credentials
+# (and similarly in struct wpa_ssid for network blocks) to change the
+# Interworking automatic networking selection behavior. The matching
+# network (based on either an enabled network block or a credential)
+# with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+# This field is used with Interworking networking selection for a case
+# where client certificate/private key is used for authentication
+# (EAP-TLS). Full path to the file should be used since working
+# directory may change when wpa_supplicant is run in the background.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key: File path to client private key file (PEM/DER/PFX)
+# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+# commented out. Both the private key and certificate will be read
+# from the PKCS#12 file in this case. Full path to the file should be
+# used since working directory may change when wpa_supplicant is run
+# in the background.
+#
+# Windows certificate store can be used by leaving client_cert out and
+# configuring private_key in one of the following formats:
+#
+# cert://substring_to_match
+#
+# hash://certificate_thumbprint_in_hex
+#
+# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#
+# Note that when running wpa_supplicant as an application, the user
+# certificate store (My user account) is used, whereas computer store
+# (Computer account) is used when running wpasvc as a service.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+# format
+#
+# domain_suffix_match: Constraint for server domain name
+# If set, this FQDN is 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 SubjetName CN
+# using same suffix match comparison. Suffix match here means that the
+# host/domain name is compared one label at a time starting from the
+# top-level domain and all the labels in @domain_suffix_match shall be
+# included in the certificate. The certificate may include additional
+# sub-level labels in addition to the required labels.
+#
+# For example, domain_suffix_match=example.com would match
+# test.example.com but would not match test-example.com.
+#
+# domain: Home service provider FQDN(s)
+# This is used to compare against the Domain Name List to figure out
+# whether the AP is operated by the Home SP. Multiple domain entries can
+# be used to configure alternative FQDNs that will be considered home
+# networks.
+#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# excluded_ssid: Excluded SSID
+# This optional field can be used to excluded specific SSID(s) from
+# matching with the network. Multiple entries can be used to specify more
+# than one SSID.
+#
+# for example:
+#
+#cred={
+# realm="example.com"
+# username="user@example.com"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# domain_suffix_match="example.com"
+#}
+#
+#cred={
+# imsi="310026-000000000"
+# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
+
+
+Control interface
+-----------------
+
+wpa_supplicant provides a control interface that can be used from
+external programs to manage various operations. The included command
+line tool, wpa_cli, can be used for manual testing with this interface.
+
+Following wpa_cli interactive mode commands show some examples of manual
+operations related to Hotspot 2.0:
+
+Remove configured networks and credentials:
+
+> remove_network all
+OK
+> remove_cred all
+OK
+
+
+Add a username/password credential:
+
+> add_cred
+0
+> set_cred 0 realm "mail.example.com"
+OK
+> set_cred 0 username "username"
+OK
+> set_cred 0 password "password"
+OK
+> set_cred 0 priority 1
+OK
+> set_cred 0 temporary 1
+OK
+
+Add a SIM credential using a simulated SIM/USIM card for testing:
+
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123"
+OK
+> set_cred 1 priority 1
+OK
+
+Note: the return value of add_cred is used as the first argument to
+the following set_cred commands.
+
+Add a SIM credential using a external SIM/USIM processing:
+
+> set external_sim 1
+OK
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 eap SIM
+OK
+
+
+Add a WPA2-Enterprise network:
+
+> add_network
+0
+> set_network 0 key_mgmt WPA-EAP
+OK
+> set_network 0 ssid "enterprise"
+OK
+> set_network 0 eap TTLS
+OK
+> set_network 0 anonymous_identity "anonymous"
+OK
+> set_network 0 identity "user"
+OK
+> set_network 0 password "password"
+OK
+> set_network 0 priority 0
+OK
+> enable_network 0 no-connect
+OK
+
+
+Add an open network:
+
+> add_network
+3
+> set_network 3 key_mgmt NONE
+OK
+> set_network 3 ssid "coffee-shop"
+OK
+> select_network 3
+OK
+
+Note: the return value of add_network is used as the first argument to
+the following set_network commands.
+
+The preferred credentials/networks can be indicated with the priority
+parameter (1 is higher priority than 0).
+
+
+Interworking network selection can be started with interworking_select
+command. This instructs wpa_supplicant to run a network scan and iterate
+through the discovered APs to request ANQP information from the APs that
+advertise support for Interworking/Hotspot 2.0:
+
+> interworking_select
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+
+
+INTERWORKING-AP event messages indicate the APs that support network
+selection and for which there is a matching
+credential. interworking_connect command can be used to select a network
+to connect with:
+
+
+> interworking_connect 02:00:00:00:01:00
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=]
+
+
+wpa_supplicant creates a temporary network block for the selected
+network based on the configured credential and ANQP information from the
+AP:
+
+> list_networks
+network id / ssid / bssid / flags
+0 Example Network any [CURRENT]
+> get_network 0 key_mgmt
+WPA-EAP
+> get_network 0 eap
+TTLS
+
+
+Alternatively to using an external program to select the network,
+"interworking_select auto" command can be used to request wpa_supplicant
+to select which network to use based on configured priorities:
+
+
+> remove_network all
+OK
+<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1
+> interworking_select auto
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=]
+
+
+The connection status can be shown with the status command:
+
+> status
+bssid=02:00:00:00:01:00
+ssid=Example Network
+id=0
+mode=station
+pairwise_cipher=CCMP <--- link layer security indication
+group_cipher=CCMP
+key_mgmt=WPA2/IEEE 802.1X/EAP
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+hs20=1 <--- HS 2.0 indication
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+selectedMethod=21 (EAP-TTLS)
+EAP TLS cipher=AES-128-SHA
+EAP-TTLSv0 Phase2 method=PAP
+
+
+> status
+bssid=02:00:00:00:02:00
+ssid=coffee-shop
+id=3
+mode=station
+pairwise_cipher=NONE
+group_cipher=NONE
+key_mgmt=NONE
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+
+
+Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status
+command output. Link layer security is indicated with the
+pairwise_cipher (CCMP = secure, NONE = no encryption used).
+
+
+Also the scan results include the Hotspot 2.0 indication:
+
+> scan_results
+bssid / frequency / signal level / flags / ssid
+02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network
+
+
+ANQP information for the BSS can be fetched using the BSS command:
+
+> bss 02:00:00:00:01:00
+id=1
+bssid=02:00:00:00:01:00
+freq=2412
+beacon_int=100
+capabilities=0x0411
+qual=0
+noise=-92
+level=-30
+tsf=1345573286517276
+age=105
+ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000
+flags=[WPA2-EAP-CCMP][ESS][HS20]
+ssid=Example Network
+anqp_roaming_consortium=031122330510203040500601020304050603fedcba
+
+
+ANQP queries can also be requested with the anqp_get and hs20_anqp_get
+commands:
+
+> anqp_get 02:00:00:00:01:00 261
+OK
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+> hs20_anqp_get 02:00:00:00:01:00 2
+OK
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+
+In addition, fetch_anqp command can be used to request similar set of
+ANQP queries to be done as is run as part of interworking_select:
+
+> scan
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+> fetch_anqp
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index db6e4ae..7354bbf 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -71,7 +71,9 @@ over the main control interface.
Device Discovery
-p2p_find [timeout in seconds] [type=<social|progressive>]
+p2p_find [timeout in seconds] [type=<social|progressive>] \
+ [dev_id=<addr>] [dev_type=<device type>] \
+ [delay=<search delay in ms>]
The default behavior is to run a single full scan in the beginning and
then scan only social channels. type=social will scan only social
@@ -81,6 +83,15 @@ progressively one channel at the time in the Search state rounds. This
will help in finding new groups or groups missed during the initial
full scan.
+The optional dev_id option can be used to specify a single P2P peer to
+search for. The optional delay parameter can be used to request an extra
+delay to be used between search iterations (e.g., to free up radio
+resources for concurrent operations).
+
+The optional dev_type option can be used to specify a single device type
+(primary or secondary) to search for, e.g.,
+"p2p_find dev_type=1-0050F204-1".
+
p2p_listen [timeout in seconds]
Start Listen-only state (become discoverable without searching for
@@ -101,7 +112,7 @@ Flush P2P peer table and state.
Group Formation
-p2p_prov_disc <peer device address> <display|keypad|pbc> [join]
+p2p_prov_disc <peer device address> <display|keypad|pbc> [join|auto]
Send P2P provision discovery request to the specified peer. The
parameters for this command are the P2P device address of the peer and
@@ -112,10 +123,14 @@ to enter a PIN that we display.
The optional "join" parameter can be used to indicate that this command
is requesting an already running GO to prepare for a new client. This is
-mainly used with "display" to request it to display a PIN.
+mainly used with "display" to request it to display a PIN. The "auto"
+parameter can be used to request wpa_supplicant to automatically figure
+out whether the peer device is operating as a GO and if so, use
+join-a-group style PD instead of GO Negotiation style PD.
p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
- [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>]
+ [persistent|persistent=<network id>] [join|auth]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -128,7 +143,12 @@ the command return code), PIN# means that a pre-selected PIN can be
used (e.g., 12345670). [display|keypad] is used with PIN method
to specify which PIN is used (display=dynamically generated random PIN
from local display, keypad=PIN entered from peer display). "persistent"
-parameter can be used to request a persistent group to be formed.
+parameter can be used to request a persistent group to be formed. The
+"persistent=<network id>" alternative can be used to pre-populate
+SSID/passphrase configuration based on a previously used persistent
+group where this device was the GO. The previously used parameters will
+then be used if the local end becomes the GO in GO Negotiation (which
+can be forced with go_intent=15).
"join" indicates that this is a command to join an existing group as a
client. It skips the GO Negotiation part. This will send a Provision
@@ -146,7 +166,13 @@ Negotiation.
"freq" can be used to set a forced operating channel (e.g., freq=2412
to select 2.4 GHz channel 1).
+"provdisc" can be used to request a Provision Discovery exchange to be
+used prior to starting GO Negotiation as a workaround with some deployed
+P2P implementations that require this to allow the user to accept the
+connection.
+
p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+ [ht40] [vht]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -171,7 +197,21 @@ group interface is used as a parameter for this command.
p2p_cancel
-Cancel an ongoing P2P group formation related operation.
+Cancel an ongoing P2P group formation and joining-a-group related
+operation. This operations 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
+step. If the WPS provisioning step has been completed, the group is not
+terminated.
+
+p2p_remove_client <peer's P2P Device Address|iface=<interface address>>
+
+This command can be used to remove the specified client from all groups
+(operating and persistent) from the local GO. Note that the peer device
+can rejoin the group if it is in possession of a valid key. See p2p_set
+per_sta_psk command below for more details on how the peer can be
+removed securely.
Service Discovery
@@ -199,6 +239,19 @@ This command returns an identifier for the pending query (e.g.,
will be automatically removed when the specified peer has replied to
it.
+Service Query TLV has following format:
+Length (2 octets, little endian) - length of following data
+Service Protocol Type (1 octet) - see the table below
+Service Transaction ID (1 octet) - nonzero identifier for the TLV
+Query Data (Length - 2 octets of data) - service protocol specific data
+
+Service Protocol Types:
+0 = All service protocols
+1 = Bonjour
+2 = UPnP
+3 = WS-Discovery
+4 = Wi-Fi Display
+
For UPnP, an alternative command format can be used to specify a
single query TLV (i.e., a service discovery for a specific UPnP
service):
@@ -236,6 +289,14 @@ p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:Content
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+# Wi-Fi Display examples
+# format: wifi-display <list of roles> <list of subelements>
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
+p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
+
p2p_serv_disc_cancel_req <query identifier>
Cancel a pending P2P service discovery request. This command takes a
@@ -318,15 +379,21 @@ Remove all local services from internal SD query processing.
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+ [pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
persistent group (e.g., persistent=4). If the peer device is the GO of
-the persisten group, the peer parameter is not needed. Otherwise it is
+the persistent group, the peer parameter is not needed. Otherwise it is
used to specify which device to invite. go_dev_addr parameter can be
used to override the GO device address for Invitation Request should
it be not known for some reason (this should not be needed in most
-cases).
+cases). When reinvoking a persistent group, the GO device can specify
+the frequency for the group with the freq parameter. When reinvoking a
+persistent group, the P2P client device can use freq parameter to force
+a specific operating channel (or invitation failure if GO rejects that)
+or pref parameter to request a specific channel (while allowing GO to
+select to use another channel, if needed).
Group Operations
@@ -356,9 +423,11 @@ p2p_presence_req [<duration> <interval>] [<duration> <interval>]
Send a P2P Presence Request to the GO (this is only available when
acting as a P2P client). If no duration/interval pairs are given, the
request indicates that this client has no special needs for GO
-presence. the first parameter pair gives the preferred duration and
+presence. The first parameter pair gives the preferred duration and
interval values in microseconds. If the second pair is included, that
-indicates which value would be acceptable.
+indicates which value would be acceptable. This command returns OK
+immediately and the response from the GO is indicated in a
+P2P-PRESENCE-RESPONSE event message.
Parameters
@@ -404,6 +473,20 @@ Set postfix string to be added to the automatically generated P2P SSID
(DIRECT-<two random characters>). For example, postfix of "-testing"
could result in the SSID becoming DIRECT-ab-testing.
+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
+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
+learned previously is still valid. It should be noted that the default
+passphrase on the GO that is normally used to allow legacy stations to
+connect through manual configuration does not change here, so if that is
+shared, devices with knowledge of that passphrase can still connect.
+
set <field> <value>
Set global configuration parameters which may also affect P2P
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index bf75cb4..18b0cca 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -67,6 +67,10 @@ will also need to add following line:
CONFIG_WPS_ER=y
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
the device. This is configured in the runtime configuration for
@@ -126,6 +130,12 @@ wpa_cli wps_pin any 12345670
This starts the WPS negotiation in the same way as above with the
generated PIN.
+When the wps_pin command is issued for an AP (including P2P GO) mode
+interface, an optional timeout parameter can be used to specify
+expiration timeout for the PIN in seconds. For example:
+
+wpa_cli wps_pin any 12345670 300
+
If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
can be used to generate a new PIN without starting WPS negotiation.
@@ -249,16 +259,16 @@ wps_er_start [IP address]
wps_er_stop
- stop WPS ER functionality
-wps_er_learn <UUID> <AP PIN>
+wps_er_learn <UUID|BSSID> <AP PIN>
- learn AP configuration
-wps_er_set_config <UUID> <network id>
+wps_er_set_config <UUID|BSSID> <network id>
- use AP configuration from a locally configured network (e.g., from
wps_reg command); this does not change the AP's configuration, but
only prepares a configuration to be used when enrolling a new device
to the AP
-wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+wps_er_config <UUID|BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
- examples:
wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
@@ -267,10 +277,10 @@ wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
<encr> must be one of the following: NONE WEP TKIP CCMP
-wps_er_pbc <Enrollee UUID>
+wps_er_pbc <Enrollee UUID|MAC address>
- accept an Enrollee PBC using External Registrar
-wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+wps_er_pin <Enrollee UUID|"any"|MAC address> <PIN> [Enrollee MAC address]
- add an Enrollee PIN to External Registrar
- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
- if the MAC address of the enrollee is known, it should be configured
@@ -303,3 +313,99 @@ WPS-ER-AP-SETTINGS
- WPS ER learned AP settings
WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the station acts as an Enrollee, a local NFC tag with a password
+token can be used by touching the NFC interface of a Registrar.
+
+"wps_nfc [BSSID]" command starts WPS protocol run with the local end as
+the Enrollee using the NFC password token that is either pre-configured
+in the configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The included nfc_pw_token tool
+(build with "make nfc_pw_token") can be used to generate NFC password
+tokens during manufacturing (each station needs to have its own random
+keys).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token when wpa_supplicant is controlling an AP
+interface (AP or P2P GO). The output value from this command is a
+hexdump of the current AP configuration (WPS parameter requests this to
+include only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+The "wps_nfc_config_token <WPS/NDEF> <network id>" command can be used
+to build an NFC configuration token based on a locally configured
+network.
+
+If the station includes NFC interface and reads an NFC tag with a MIME
+media type "application/vnd.wfa.wsc", the NDEF message payload (with or
+without NDEF encapsulation) can be delivered to wpa_supplicant using the
+following wpa_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a configuration token, the network is added to
+wpa_supplicant configuration. If the NFC tag contains a password token,
+the token is added to the WPS Registrar component. This information can
+then be used with wps_reg command (when the NFC password token was from
+an AP) using a special value "nfc-pw" in place of the PIN parameter. If
+the ER functionality has been started (wps_er_start), the NFC password
+token is used to enable enrollment of a new station (that was the source
+of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS-CR>" command can be used to build the
+WPS carrier record for a Handover Request Message for connection
+handover. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS-CR = Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS> [UUID|BSSID]" command can be used to
+build the contents of a Handover Select Message for connection handover
+when this does not depend on the contents of the Handover Request
+Message. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS = Wi-Fi handover as specified in WSC 2.0). If the options
+UUID|BSSID argument is included, this is a request to build the handover
+message for the specified AP when wpa_supplicant is operating as a WPS
+ER.
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" can be used as an alternative way for
+reporting completed NFC connection handover. The first parameter
+indicates whether the local device initiated or responded to the
+connection handover and the carrier records are the selected carrier
+from the handover request and select messages as a hexdump.
+
+The "wps_er_nfc_config_token <WPS/NDEF> <UUID|BSSID>" command can be
+used to build an NFC configuration token for the specified AP when
+wpa_supplicant is operating as a WPS ER. The output value from this
+command is a hexdump of the selected AP configuration (WPS parameter
+requests this to include only the WPS attributes; NDEF parameter
+requests additional NDEF encapsulation to be included). This data needs
+to be written to an NFC tag with an external program. Once written, the
+NFC configuration token can be used to touch an NFC interface on a
+station to provision the credentials needed to access the network.
diff --git a/wpa_supplicant/README-Windows.txt b/wpa_supplicant/README-Windows.txt
index 292223d..7288abd 100644
--- a/wpa_supplicant/README-Windows.txt
+++ b/wpa_supplicant/README-Windows.txt
@@ -4,13 +4,8 @@ wpa_supplicant for Windows
Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-This product includes software developed by the OpenSSL Project
-for use in the OpenSSL Toolkit (http://www.openssl.org/). This
-product includes cryptographic software written by Eric Young
-(eay@cryptsoft.com).
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
@@ -35,20 +30,6 @@ authentication and successfully ping a wired host):
- WPA2-EAP, TKIP, CCMP, TKIP+CCMP
-Binary version
---------------
-
-Compiled binary version of the wpa_supplicant and additional tools is
-available from http://w1.fi/wpa_supplicant/. These binaries can be
-used after installing WinPcap.
-
-wpa_gui uses Qt 4 framework and may need additional dynamic libraries
-(DLLs). These libraries are available from
-http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
-You can copy the DLL files from this ZIP package into the same directory
-with wpa_gui.exe to allow wpa_gui to be started.
-
-
Building wpa_supplicant with mingw
----------------------------------
@@ -316,135 +297,3 @@ HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
See win_example.reg for an example on how to setup wpasvc.exe
parameters in registry. It can also be imported to registry as a
starting point for the configuration.
-
-
-
-License information for third party software used in this product:
-
- OpenSSL License
- ---------------
-
-/* ====================================================================
- * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
- Original SSLeay License
- -----------------------
-
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-
-
- Qt Open Source Edition
- ----------------------
-
-The Qt GUI Toolkit is Copyright (C) 1994-2007 Trolltech ASA.
-Qt Open Source Edition is licensed under GPL version 2.
-
-Source code for the library is available at
-http://w1.fi/wpa_supplicant/qt4/qt-win-opensource-src-4.3.3.zip
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
new file mode 100644
index 0000000..184b41e
--- /dev/null
+++ b/wpa_supplicant/android.config
@@ -0,0 +1,481 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+#CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+CONFIG_LIBNL20=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Driver interface for wired Ethernet drivers
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable WSC 2.0 support
+CONFIG_WPS2=y
+# Enable WPS external registrar functionality
+CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+# path is given on command line, not here; this option is just used to
+# select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+CONFIG_ANDROID_LOG=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+CONFIG_IEEE80211N=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+CONFIG_HS20=y
+
+# Disable roaming in wpa_supplicant
+CONFIG_NO_ROAMING=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+CONFIG_P2P=y
+
+# Enable TDLS support
+CONFIG_TDLS=y
+
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
+
+include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 75b1393..ce3efcb 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -3,14 +3,8 @@
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -20,6 +14,8 @@
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "crypto/dh_group5.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
@@ -30,9 +26,6 @@
#include "ap/ieee802_1x.h"
#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
-#include "eap_common/eap_defs.h"
-#include "eap_server/eap_methods.h"
-#include "eap_common/eap_wsc_common.h"
#include "wps/wps.h"
#include "common/ieee802_11_defs.h"
#include "config_ssid.h"
@@ -50,29 +43,46 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211N
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+ struct hostapd_config *conf,
+ struct hostapd_hw_modes *mode)
+{
+ u8 center_chan = 0;
+ u8 channel = conf->channel;
+
+ if (!conf->secondary_channel)
+ goto no_vht;
+
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ 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;
+
+no_vht:
+ conf->vht_oper_centr_freq_seg0_idx =
+ channel + conf->secondary_channel * 2;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf)
{
- struct hostapd_bss_config *bss = &conf->bss[0];
- int pairwise;
+ struct hostapd_bss_config *bss = conf->bss[0];
conf->driver = wpa_s->driver;
os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
- if (ssid->frequency == 0) {
- /* default channel 11 */
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = 11;
- } else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = (ssid->frequency - 2407) / 5;
- } else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
- (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
- conf->channel = (ssid->frequency - 5000) / 5;
- } else {
+ 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;
@@ -83,26 +93,68 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211N
/*
- * Enable HT20 if the driver supports it, by setting conf->ieee80211n.
+ * Enable HT20 if the driver supports it, by setting conf->ieee80211n
+ * and a mask of allowed capabilities within conf->ht_capab.
* Using default config settings for: conf->ht_op_mode_fixed,
- * conf->ht_capab, conf->secondary_channel, conf->require_ht
+ * conf->secondary_channel, conf->require_ht
*/
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
- int i;
+ int i, no_ht = 0;
for (i = 0; i < wpa_s->hw.num_modes; i++) {
if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
mode = &wpa_s->hw.modes[i];
break;
}
}
- if (mode && mode->ht_capab)
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ conf->ieee80211n = 0;
+ conf->ht_capab = 0;
+ no_ht = 1;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
+ if (!no_ht && mode && mode->ht_capab) {
conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ ssid->ht40)
+ conf->secondary_channel =
+ wpas_p2p_get_ht40_mode(wpa_s, mode,
+ conf->channel);
+ if (conf->secondary_channel)
+ conf->ht_capab |=
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif /* CONFIG_P2P */
+
+ /*
+ * white-list capabilities that won't cause issues
+ * to connecting stations, while leaving the current
+ * capabilities intact (currently disabled SMPS).
+ */
+ conf->ht_capab |= mode->ht_capab &
+ (HT_CAP_INFO_GREEN_FIELD |
+ HT_CAP_INFO_SHORT_GI20MHZ |
+ HT_CAP_INFO_SHORT_GI40MHZ |
+ HT_CAP_INFO_RX_STBC_MASK |
+ HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+ if (mode->vht_capab && ssid->vht) {
+ conf->ieee80211ac = 1;
+ wpas_conf_ap_vht(wpa_s, conf, mode);
+ }
+ }
}
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P
- if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
+ (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) {
/* Remove 802.11b rates from supported and basic rate sets */
int *list = os_malloc(4 * sizeof(int));
if (list) {
@@ -129,6 +181,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
bss->isolate = !wpa_s->conf->p2p_intra_bss;
+ 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,
+ 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,
+ 4);
+ }
#endif /* CONFIG_P2P */
if (ssid->ssid_len == 0) {
@@ -136,10 +199,11 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
return -1;
}
os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
- bss->ssid.ssid[ssid->ssid_len] = '\0';
bss->ssid.ssid_len = ssid->ssid_len;
bss->ssid.ssid_set = 1;
+ bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid;
+
if (ssid->auth_alg)
bss->auth_algs = ssid->auth_alg;
@@ -147,15 +211,15 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa = ssid->proto;
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->passphrase) {
- bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
- } else if (ssid->psk_set) {
+ if (ssid->psk_set) {
os_free(bss->ssid.wpa_psk);
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
return -1;
os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
bss->ssid.wpa_psk->group = 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] ||
ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -174,19 +238,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
wep->keys_set = 1;
}
- /* Select group cipher based on the enabled pairwise cipher suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
- }
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
+ if (ssid->ap_max_inactivity)
+ bss->ap_max_inactivity = ssid->ap_max_inactivity;
+
+ if (ssid->dtim_period)
+ bss->dtim_period = ssid->dtim_period;
+ else if (wpa_s->conf->dtim_period)
+ bss->dtim_period = wpa_s->conf->dtim_period;
+
+ if (ssid->beacon_int)
+ conf->beacon_int = ssid->beacon_int;
+ else if (wpa_s->conf->beacon_int)
+ conf->beacon_int = wpa_s->conf->beacon_int;
+
+ if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+ bss->rsn_pairwise);
if (bss->wpa && bss->ieee802_1x)
bss->ssid.security_policy = SECURITY_WPA;
@@ -217,6 +285,18 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->rsn_pairwise = WPA_CIPHER_NONE;
}
+ if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
+ (bss->wpa_group == WPA_CIPHER_CCMP ||
+ bss->wpa_group == WPA_CIPHER_GCMP ||
+ bss->wpa_group == WPA_CIPHER_CCMP_256 ||
+ bss->wpa_group == WPA_CIPHER_GCMP_256)) {
+ /*
+ * Strong ciphers do not need frequent rekeying, so increase
+ * the default GTK rekeying period to 24 hours.
+ */
+ bss->wpa_group_rekey = 86400;
+ }
+
#ifdef CONFIG_WPS
/*
* Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -228,12 +308,15 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
goto no_wps;
#ifdef CONFIG_WPS2
if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
- (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+ (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
#endif /* CONFIG_WPS2 */
bss->eap_server = 1;
- bss->wps_state = 2;
+
+ if (!ssid->ignore_broadcast_ssid)
+ bss->wps_state = 2;
+
bss->ap_setup_locked = 2;
if (wpa_s->conf->config_methods)
bss->config_methods = os_strdup(wpa_s->conf->config_methods);
@@ -256,6 +339,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
else
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;
no_wps:
#endif /* CONFIG_WPS */
@@ -267,6 +351,11 @@ no_wps:
bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+ if (wpa_s->conf->ap_vendor_elements) {
+ bss->vendor_elements =
+ wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+ }
+
return 0;
}
@@ -282,6 +371,8 @@ static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
if (hdr_len > len)
return;
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+ return;
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
mgmt->u.action.category,
&mgmt->u.action.u.vs_public_action.action,
@@ -323,6 +414,19 @@ static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
}
+#ifdef CONFIG_P2P
+static void ap_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
+ const u8 *psk, size_t psk_len)
+{
+
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL)
+ return;
+ wpas_p2p_new_psk_cb(wpa_s, mac_addr, p2p_dev_addr, psk, psk_len);
+}
+#endif /* CONFIG_P2P */
+
+
static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
{
#ifdef CONFIG_P2P
@@ -344,11 +448,13 @@ static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
#ifdef CONFIG_P2P
struct wpa_supplicant *wpa_s = ctx;
- return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len);
+ return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+ ssi_signal);
#else /* CONFIG_P2P */
return 0;
#endif /* CONFIG_P2P */
@@ -411,6 +517,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.mode = IEEE80211_MODE_AP;
break;
}
+ if (ssid->frequency == 0)
+ ssid->frequency = 2462; /* default channel 11 */
params.freq = ssid->frequency;
params.wpa_proto = ssid->proto;
@@ -418,20 +526,16 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
- params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
-
- if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
- wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- else {
+ params.key_mgmt_suite = wpa_s->key_mgmt;
+
+ wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher,
+ 1);
+ if (wpa_s->pairwise_cipher < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
"cipher.");
return -1;
}
- params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+ params.pairwise_suite = wpa_s->pairwise_cipher;
params.group_suite = params.pairwise_suite;
#ifdef CONFIG_P2P
@@ -455,6 +559,10 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
+ hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+ hapd_iface->extended_capa = wpa_s->extended_capa;
+ hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
+ hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
@@ -462,9 +570,13 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
}
+ os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
+ wpa_s->conf->wmm_ac_params,
+ sizeof(wpa_s->conf->wmm_ac_params));
+
if (params.uapsd > 0) {
- conf->bss->wmm_enabled = 1;
- conf->bss->wmm_uapsd = 1;
+ conf->bss[0]->wmm_enabled = 1;
+ conf->bss[0]->wmm_uapsd = 1;
}
if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
@@ -475,14 +587,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_P2P
if (ssid->mode == WPAS_MODE_P2P_GO)
- conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+ conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
- conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+ conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
P2P_GROUP_FORMATION;
#endif /* CONFIG_P2P */
hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL) {
wpa_supplicant_ap_deinit(wpa_s);
@@ -492,7 +604,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
for (i = 0; i < conf->num_bss; i++) {
hapd_iface->bss[i] =
hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
+ conf->bss[i]);
if (hapd_iface->bss[i] == NULL) {
wpa_supplicant_ap_deinit(wpa_s);
return -1;
@@ -513,10 +625,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
#ifdef CONFIG_P2P
+ hapd_iface->bss[i]->new_psk_cb = ap_new_psk_cb;
+ hapd_iface->bss[i]->new_psk_cb_ctx = wpa_s;
hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
- hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(
- wpa_s, ssid->p2p_persistent_group,
- ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+ hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
+ ssid);
#endif /* CONFIG_P2P */
hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
@@ -527,6 +640,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
wpa_s->current_ssid = ssid;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
@@ -550,8 +664,8 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
return;
wpa_s->current_ssid = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->assoc_freq = 0;
- wpa_s->reassociated_connection = 0;
#ifdef CONFIG_P2P
if (wpa_s->ap_iface->bss)
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
@@ -574,6 +688,18 @@ void ap_tx_status(void *ctx, const u8 *addr,
}
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+ const u8 *data, size_t len, int ack)
+{
+#ifdef NEED_AP_MLME
+ struct wpa_supplicant *wpa_s = ctx;
+ if (!wpa_s->ap_iface)
+ return;
+ hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
+#endif /* NEED_AP_MLME */
+}
+
+
void ap_client_poll_ok(void *ctx, const u8 *addr)
{
#ifdef NEED_AP_MLME
@@ -635,21 +761,6 @@ int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
-static int wpa_supplicant_ap_wps_sta_cancel(struct hostapd_data *hapd,
- struct sta_info *sta, void *ctx)
-{
- if (sta && (sta->flags & WLAN_STA_WPS)) {
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
- __func__, MAC2STR(sta->addr));
- return 1;
- }
-
- return 0;
-}
-
-
int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
{
struct wps_registrar *reg;
@@ -661,7 +772,7 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
reg = wpa_s->ap_iface->bss[0]->wps->registrar;
reg_sel = wps_registrar_wps_cancel(reg);
wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
- wpa_supplicant_ap_wps_sta_cancel, NULL);
+ ap_sta_wps_cancel, NULL);
if (!reg_sel && !wps_sta) {
wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
@@ -681,7 +792,8 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, char *buf, size_t buflen)
+ const char *pin, char *buf, size_t buflen,
+ int timeout)
{
int ret, ret_len = 0;
@@ -696,7 +808,7 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
ret_len = os_snprintf(buf, buflen, "%s", pin);
ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
- 0);
+ timeout);
if (ret)
return -1;
return ret_len;
@@ -819,6 +931,47 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
hapd->conf->ap_pin = NULL;
}
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_hs_cr(hapd, ndef);
+}
+
+
+int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_report_handover(hapd, req, sel);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
#endif /* CONFIG_WPS */
@@ -854,6 +1007,26 @@ int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
}
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_disassociate(wpa_s->ap_iface->bss[0],
+ txtaddr);
+}
+
+
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_deauthenticate(wpa_s->ap_iface->bss[0],
+ txtaddr);
+}
+
+
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose)
{
@@ -898,9 +1071,9 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_P2P
if (ssid->mode == WPAS_MODE_P2P_GO)
- iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+ iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
- iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+ iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
P2P_GROUP_FORMATION;
#endif /* CONFIG_P2P */
@@ -914,6 +1087,43 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
}
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings)
+{
+#ifdef NEED_AP_MLME
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return -1;
+
+ return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+#else /* NEED_AP_MLME */
+ return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
+{
+ struct csa_settings settings;
+ int ret = hostapd_parse_csa_settings(pos, &settings);
+
+ if (ret)
+ return ret;
+
+ return ap_switch_channel(wpa_s, &settings);
+}
+
+
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+ int offset, int width, int cf1, int cf2)
+{
+ if (!wpa_s->ap_iface)
+ return;
+
+ wpa_s->assoc_freq = freq;
+ hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
+}
+
+
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
@@ -953,3 +1163,48 @@ int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
return 0;
}
+
+
+#ifdef CONFIG_WPS_NFC
+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_data *hapd;
+ struct wps_context *wps;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+ 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) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
+ return -1;
+ }
+
+ dh5_free(wps->dh_ctx);
+ wpabuf_free(wps->dh_pubkey);
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = wpabuf_dup(
+ wpa_s->parent->conf->wps_nfc_dh_privkey);
+ wps->dh_pubkey = wpabuf_dup(
+ wpa_s->parent->conf->wps_nfc_dh_pubkey);
+ if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+ wps->dh_ctx = NULL;
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ return -1;
+ }
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+ if (wps->dh_ctx == NULL)
+ return -1;
+
+ return wps_registrar_add_nfc_pw_token(hapd->wps->registrar, pubkey_hash,
+ pw_id,
+ pw ? wpabuf_head(pw) : NULL,
+ pw ? wpabuf_len(pw) : 0, 1);
+}
+#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 567e784..8aa5ffa 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -3,14 +3,8 @@
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef AP_H
@@ -24,7 +18,8 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *p2p_dev_addr);
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, char *buf, size_t buflen);
+ const char *pin, char *buf, size_t buflen,
+ int timeout);
int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
@@ -37,10 +32,16 @@ int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr);
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr);
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose);
void ap_tx_status(void *ctx, const u8 *addr,
const u8 *buf, size_t len, int ack);
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+ const u8 *data, size_t len, int ack);
void ap_client_poll_ok(void *ctx, const u8 *addr);
void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds);
void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
@@ -49,5 +50,29 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr);
void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings);
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+ int offset, int width, int cf1, int cf2);
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef);
+#ifdef CONFIG_AP
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef);
+#else /* CONFIG_AP */
+static inline struct wpabuf *
+wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ return NULL;
+}
+#endif /* CONFIG_AP */
+
+int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
+int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
+ const struct wpabuf *pw, const u8 *pubkey_hash);
#endif /* AP_H */
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
new file mode 100644
index 0000000..a2cf7a5
--- /dev/null
+++ b/wpa_supplicant/autoscan.c
@@ -0,0 +1,143 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#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
+ &autoscan_exponential_ops,
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+ &autoscan_periodic_ops,
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+ NULL
+};
+
+
+static void request_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+
+ if (wpa_supplicant_req_sched_scan(wpa_s))
+ wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
+}
+
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+ const char *name = wpa_s->conf->autoscan;
+ const char *params;
+ size_t nlen;
+ int i;
+ const struct autoscan_ops *ops = NULL;
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv)
+ return 0;
+
+ if (name == NULL)
+ return 0;
+
+ params = os_strchr(name, ':');
+ if (params == NULL) {
+ params = "";
+ nlen = os_strlen(name);
+ } else {
+ nlen = params - name;
+ params++;
+ }
+
+ for (i = 0; autoscan_modules[i]; i++) {
+ if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
+ ops = autoscan_modules[i];
+ break;
+ }
+ }
+
+ if (ops == NULL) {
+ wpa_printf(MSG_ERROR, "autoscan: Could not find module "
+ "matching the parameter '%s'", name);
+ return -1;
+ }
+
+ wpa_s->autoscan_params = NULL;
+
+ wpa_s->autoscan_priv = ops->init(wpa_s, params);
+ if (wpa_s->autoscan_priv == NULL)
+ return -1;
+ wpa_s->autoscan = ops;
+
+ wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
+ "parameters '%s'", ops->name, params);
+ if (!req_scan)
+ return 0;
+
+ /*
+ * Cancelling existing scan requests, if any.
+ */
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /*
+ * Firing first scan, which will lead to call autoscan_notify_scan.
+ */
+ request_scan(wpa_s);
+
+ return 0;
+}
+
+
+void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
+ wpa_s->autoscan->name);
+ wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
+ wpa_s->autoscan = NULL;
+ wpa_s->autoscan_priv = NULL;
+
+ wpa_s->scan_interval = 5;
+ wpa_s->sched_scan_interval = 0;
+ }
+}
+
+
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ int interval;
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
+ scan_res);
+
+ if (interval <= 0)
+ return -1;
+
+ wpa_s->scan_interval = interval;
+ wpa_s->sched_scan_interval = interval;
+
+ request_scan(wpa_s);
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
new file mode 100644
index 0000000..e2a7652
--- /dev/null
+++ b/wpa_supplicant/autoscan.h
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTOSCAN_H
+#define AUTOSCAN_H
+
+struct wpa_supplicant;
+
+struct autoscan_ops {
+ const char *name;
+
+ void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
+ void (*deinit)(void *priv);
+
+ int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+};
+
+#ifdef CONFIG_AUTOSCAN
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan);
+void autoscan_deinit(struct wpa_supplicant *wpa_s);
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+
+#else /* CONFIG_AUTOSCAN */
+
+static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+ return 0;
+}
+
+static inline void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+#endif /* AUTOSCAN_H */
diff --git a/wpa_supplicant/autoscan_exponential.c b/wpa_supplicant/autoscan_exponential.c
new file mode 100644
index 0000000..424477b
--- /dev/null
+++ b/wpa_supplicant/autoscan_exponential.c
@@ -0,0 +1,104 @@
+/*
+ * WPA Supplicant - auto scan exponential module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+struct autoscan_exponential_data {
+ struct wpa_supplicant *wpa_s;
+ int base;
+ int limit;
+ int interval;
+};
+
+
+static int
+autoscan_exponential_get_params(struct autoscan_exponential_data *data,
+ const char *params)
+{
+ const char *pos;
+
+ if (params == NULL)
+ return -1;
+
+ data->base = atoi(params);
+
+ pos = os_strchr(params, ':');
+ if (pos == NULL)
+ return -1;
+
+ pos++;
+ data->limit = atoi(pos);
+
+ return 0;
+}
+
+
+static void * autoscan_exponential_init(struct wpa_supplicant *wpa_s,
+ const char *params)
+{
+ struct autoscan_exponential_data *data;
+
+ data = os_zalloc(sizeof(struct autoscan_exponential_data));
+ if (data == NULL)
+ return NULL;
+
+ if (autoscan_exponential_get_params(data, params) < 0) {
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "autoscan exponential: base exponential is %d "
+ "and limit is %d", data->base, data->limit);
+
+ data->wpa_s = wpa_s;
+
+ return data;
+}
+
+
+static void autoscan_exponential_deinit(void *priv)
+{
+ struct autoscan_exponential_data *data = priv;
+
+ os_free(data);
+}
+
+
+static int autoscan_exponential_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct autoscan_exponential_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "autoscan exponential: scan result "
+ "notification");
+
+ if (data->interval >= data->limit)
+ return data->limit;
+
+ if (data->interval <= 0)
+ data->interval = data->base;
+ else {
+ data->interval = data->interval * data->base;
+ if (data->interval > data->limit)
+ return data->limit;
+ }
+
+ return data->interval;
+}
+
+
+const struct autoscan_ops autoscan_exponential_ops = {
+ .name = "exponential",
+ .init = autoscan_exponential_init,
+ .deinit = autoscan_exponential_deinit,
+ .notify_scan = autoscan_exponential_notify_scan,
+};
diff --git a/wpa_supplicant/autoscan_periodic.c b/wpa_supplicant/autoscan_periodic.c
new file mode 100644
index 0000000..102d723
--- /dev/null
+++ b/wpa_supplicant/autoscan_periodic.c
@@ -0,0 +1,85 @@
+/*
+ * WPA Supplicant - auto scan periodic module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+
+struct autoscan_periodic_data {
+ int periodic_interval;
+};
+
+
+static int autoscan_periodic_get_params(struct autoscan_periodic_data *data,
+ const char *params)
+{
+ int interval;
+
+ if (params == NULL)
+ return -1;
+
+ interval = atoi(params);
+
+ if (interval < 0)
+ return -1;
+
+ data->periodic_interval = interval;
+
+ return 0;
+}
+
+
+static void * autoscan_periodic_init(struct wpa_supplicant *wpa_s,
+ const char *params)
+{
+ struct autoscan_periodic_data *data;
+
+ data = os_zalloc(sizeof(struct autoscan_periodic_data));
+ if (data == NULL)
+ return NULL;
+
+ if (autoscan_periodic_get_params(data, params) < 0) {
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "autoscan periodic: interval is %d",
+ data->periodic_interval);
+
+ return data;
+}
+
+
+static void autoscan_periodic_deinit(void *priv)
+{
+ struct autoscan_periodic_data *data = priv;
+
+ os_free(data);
+}
+
+
+static int autoscan_periodic_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct autoscan_periodic_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "autoscan periodic: scan result notification");
+
+ return data->periodic_interval;
+}
+
+
+const struct autoscan_ops autoscan_periodic_ops = {
+ .name = "periodic",
+ .init = autoscan_periodic_init,
+ .deinit = autoscan_periodic_deinit,
+ .notify_scan = autoscan_periodic_notify_scan,
+};
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 5661830..f74cdbf 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming interface
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -37,9 +31,9 @@ static const struct bgscan_ops * bgscan_modules[] = {
};
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const char *name)
{
- const char *name = ssid->bgscan;
const char *params;
size_t nlen;
int i;
@@ -47,7 +41,7 @@ int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
bgscan_deinit(wpa_s);
if (name == NULL)
- return 0;
+ return -1;
params = os_strchr(name, ':');
if (params == NULL) {
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index ae94a48..9131e4e 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming interface
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BGSCAN_H
@@ -35,7 +29,8 @@ struct bgscan_ops {
#ifdef CONFIG_BGSCAN
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const char *name);
void bgscan_deinit(struct wpa_supplicant *wpa_s);
int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -47,7 +42,7 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
#else /* CONFIG_BGSCAN */
static inline int bgscan_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid, const char name)
{
return 0;
}
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index 5385cce..6a92b73 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming module: learn
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -40,7 +34,7 @@ struct bgscan_learn_data {
int signal_threshold;
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
- struct os_time last_bgscan;
+ struct os_reltime last_bgscan;
char *fname;
struct dl_list bss;
int *supp_freqs;
@@ -81,7 +75,7 @@ static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
return;
- n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN);
+ n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
if (n == NULL)
return;
@@ -225,7 +219,7 @@ static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
if (in_array(freqs, bss->freq))
continue;
- n = os_realloc(freqs, (*count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, *count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
@@ -246,15 +240,15 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
if (data->supp_freqs == NULL)
return freqs;
- idx = data->probe_idx + 1;
- while (idx != data->probe_idx) {
- if (data->supp_freqs[idx] == 0)
- idx = 0;
+ idx = data->probe_idx;
+ do {
if (!in_array(freqs, data->supp_freqs[idx])) {
wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
"%u", data->supp_freqs[idx]);
- data->probe_idx = idx;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ data->probe_idx = idx + 1;
+ if (data->supp_freqs[data->probe_idx] == 0)
+ data->probe_idx = 0;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
@@ -265,7 +259,9 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
}
idx++;
- }
+ if (data->supp_freqs[idx] == 0)
+ idx = 0;
+ } while (idx != data->probe_idx);
return freqs;
}
@@ -314,7 +310,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
eloop_register_timeout(data->scan_interval, 0,
bgscan_learn_timeout, data, NULL);
} else
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
os_free(freqs);
}
@@ -366,7 +362,10 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
for (j = 0; j < modes[i].num_channels; j++) {
if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ /* some hw modes (e.g. 11b & 11g) contain same freqs */
+ if (in_array(freqs, modes[i].channels[j].freq))
+ continue;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
continue;
@@ -422,6 +421,14 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
data->scan_interval = data->short_interval;
+ if (data->signal_threshold) {
+ /* Poll for signal info to set initial scan interval */
+ struct wpa_signal_info siginfo;
+ if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+ siginfo.current_signal >= data->signal_threshold)
+ data->scan_interval = data->long_interval;
+ }
+
eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
data, NULL);
@@ -431,7 +438,7 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
* us skip an immediate new scan in cases where the current signal
* level is below the bgscan threshold.
*/
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
return data;
}
@@ -558,7 +565,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above,
{
struct bgscan_learn_data *data = priv;
int scan = 0;
- struct os_time now;
+ struct os_reltime now;
if (data->short_interval == data->long_interval ||
data->signal_threshold == 0)
@@ -572,7 +579,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above,
wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
"interval");
data->scan_interval = data->short_interval;
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 1)
scan = 1;
} else if (data->scan_interval == data->short_interval && above) {
@@ -587,7 +594,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above,
* Signal dropped further 4 dB. Request a new scan if we have
* not yet scanned in a while.
*/
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 10)
scan = 1;
}
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index eedc961..a467cc5 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming module: simple
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -29,9 +23,10 @@ struct bgscan_simple_data {
int scan_interval;
int signal_threshold;
int short_scan_count; /* counter for scans using short scan interval */
+ int max_short_scans; /* maximum times we short-scan before back-off */
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
- struct os_time last_bgscan;
+ struct os_reltime last_bgscan;
};
@@ -66,14 +61,21 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
* scanning at the short scan interval. After that,
* revert to the long scan interval.
*/
- if (data->short_scan_count >
- data->long_interval / data->short_interval + 1) {
+ if (data->short_scan_count > data->max_short_scans) {
data->scan_interval = data->long_interval;
wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
"off to long scan interval");
}
+ } else if (data->short_scan_count > 0) {
+ /*
+ * If we lasted a long scan interval without any
+ * CQM triggers, decrease the short-scan count,
+ * which allows 1 more short-scan interval to
+ * occur in the future when CQM triggers.
+ */
+ data->short_scan_count--;
}
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
}
}
@@ -138,6 +140,7 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
}
data->scan_interval = data->short_interval;
+ data->max_short_scans = data->long_interval / data->short_interval + 1;
if (data->signal_threshold) {
/* Poll for signal info to set initial scan interval */
struct wpa_signal_info siginfo;
@@ -156,7 +159,7 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
* us skip an immediate new scan in cases where the current signal
* level is below the bgscan threshold.
*/
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
return data;
}
@@ -208,7 +211,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
{
struct bgscan_simple_data *data = priv;
int scan = 0;
- struct os_time now;
+ struct os_reltime now;
if (data->short_interval == data->long_interval ||
data->signal_threshold == 0)
@@ -222,9 +225,15 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
"bgscan interval");
data->scan_interval = data->short_interval;
- data->short_scan_count = 0;
- os_get_time(&now);
- if (now.sec > data->last_bgscan.sec + 1)
+ os_get_reltime(&now);
+ if (now.sec > data->last_bgscan.sec + 1 &&
+ data->short_scan_count <= data->max_short_scans)
+ /*
+ * If we haven't just previously (<1 second ago)
+ * performed a scan, and we haven't depleted our
+ * budget for short-scans, perform a scan
+ * immediately.
+ */
scan = 1;
else if (data->last_bgscan.sec + data->long_interval >
now.sec + data->scan_interval) {
@@ -250,7 +259,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
* Signal dropped further 4 dB. Request a new scan if we have
* not yet scanned in a while.
*/
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 10)
scan = 1;
}
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
index 8f12ac9..e53dc38 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/blacklist.c
@@ -2,14 +2,8 @@
* wpa_supplicant - Temporary BSSID blacklist
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -29,6 +23,9 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
{
struct wpa_blacklist *e;
+ if (wpa_s == NULL || bssid == NULL)
+ return NULL;
+
e = wpa_s->blacklist;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
@@ -60,6 +57,9 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
e = wpa_blacklist_get(wpa_s, bssid);
if (e) {
e->count++;
@@ -93,6 +93,9 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e, *prev = NULL;
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
e = wpa_s->blacklist;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
@@ -120,14 +123,19 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
+ int max_count = 0;
e = wpa_s->blacklist;
wpa_s->blacklist = NULL;
while (e) {
+ if (e->count > max_count)
+ max_count = e->count;
prev = e;
e = e->next;
wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
"blacklist (clear)", MAC2STR(prev->bssid));
os_free(prev);
}
+
+ wpa_s->extra_blacklist_count += max_count;
}
diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h
index de280cd..ae06986 100644
--- a/wpa_supplicant/blacklist.h
+++ b/wpa_supplicant/blacklist.h
@@ -2,14 +2,8 @@
* wpa_supplicant - Temporary BSSID blacklist
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BLACKLIST_H
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 1b27440..9ea6903 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1,15 +1,9 @@
/*
* BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -41,32 +35,185 @@
#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static void wpa_bss_set_hessid(struct wpa_bss *bss)
+{
+#ifdef CONFIG_INTERWORKING
+ const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
+ if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
+ os_memset(bss->hessid, 0, ETH_ALEN);
+ return;
+ }
+ if (ie[1] == 7)
+ os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
+ else
+ os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
+ * Returns: Allocated ANQP data structure or %NULL on failure
+ *
+ * The allocated ANQP data structure has its users count set to 1. It may be
+ * shared by multiple BSS entries and each shared entry is freed with
+ * wpa_bss_anqp_free().
+ */
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+ struct wpa_bss_anqp *anqp;
+ anqp = os_zalloc(sizeof(*anqp));
+ if (anqp == NULL)
+ return NULL;
+ anqp->users = 1;
+ return anqp;
+}
+
+
+/**
+ * wpa_bss_anqp_clone - Clone an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
+ * Returns: Cloned ANQP data structure or %NULL on failure
+ */
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
{
+ struct wpa_bss_anqp *n;
+
+ n = os_zalloc(sizeof(*n));
+ if (n == NULL)
+ return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+ ANQP_DUP(venue_name);
+ ANQP_DUP(network_auth_type);
+ ANQP_DUP(roaming_consortium);
+ ANQP_DUP(ip_addr_type_availability);
+ ANQP_DUP(nai_realm);
+ ANQP_DUP(anqp_3gpp);
+ ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ ANQP_DUP(hs20_operator_friendly_name);
+ ANQP_DUP(hs20_wan_metrics);
+ ANQP_DUP(hs20_connection_capability);
+ ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+ return n;
+}
+
+
+/**
+ * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
+ * @bss: BSS entry
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function ensures the specific BSS entry has an ANQP data structure that
+ * is not shared with any other BSS entry.
+ */
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+ struct wpa_bss_anqp *anqp;
+
+ if (bss->anqp && bss->anqp->users > 1) {
+ /* allocated, but shared - clone an unshared copy */
+ anqp = wpa_bss_anqp_clone(bss->anqp);
+ if (anqp == NULL)
+ return -1;
+ anqp->users = 1;
+ bss->anqp->users--;
+ bss->anqp = anqp;
+ return 0;
+ }
+
+ if (bss->anqp)
+ return 0; /* already allocated and not shared */
+
+ /* not allocated - allocate a new storage area */
+ bss->anqp = wpa_bss_anqp_alloc();
+ return bss->anqp ? 0 : -1;
+}
+
+
+/**
+ * wpa_bss_anqp_free - Free an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
+ */
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+ if (anqp == NULL)
+ return;
+
+ anqp->users--;
+ if (anqp->users > 0) {
+ /* Another BSS entry holds a pointer to this ANQP info */
+ return;
+ }
+
+#ifdef CONFIG_INTERWORKING
+ wpabuf_free(anqp->venue_name);
+ wpabuf_free(anqp->network_auth_type);
+ wpabuf_free(anqp->roaming_consortium);
+ wpabuf_free(anqp->ip_addr_type_availability);
+ wpabuf_free(anqp->nai_realm);
+ wpabuf_free(anqp->anqp_3gpp);
+ wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ wpabuf_free(anqp->hs20_wan_metrics);
+ wpabuf_free(anqp->hs20_connection_capability);
+ wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+ os_free(anqp);
+}
+
+
+static 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;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (wpa_s->last_scan_res[i] == bss) {
+ os_memmove(&wpa_s->last_scan_res[i],
+ &wpa_s->last_scan_res[i + 1],
+ (wpa_s->last_scan_res_used - i - 1)
+ * sizeof(struct wpa_bss *));
+ wpa_s->last_scan_res_used--;
+ break;
+ }
+ }
+ }
dl_list_del(&bss->list);
dl_list_del(&bss->list_id);
wpa_s->num_bss--;
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
- " SSID '%s'", bss->id, MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
-#ifdef CONFIG_INTERWORKING
- wpabuf_free(bss->anqp_venue_name);
- wpabuf_free(bss->anqp_network_auth_type);
- wpabuf_free(bss->anqp_roaming_consortium);
- wpabuf_free(bss->anqp_ip_addr_type_availability);
- wpabuf_free(bss->anqp_nai_realm);
- wpabuf_free(bss->anqp_3gpp);
- wpabuf_free(bss->anqp_domain_name);
-#endif /* CONFIG_INTERWORKING */
+ wpa_bss_anqp_free(bss->anqp);
os_free(bss);
}
+/**
+ * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len)
{
struct wpa_bss *bss;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
bss->ssid_len == ssid_len &&
@@ -77,10 +224,27 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+static void calculate_update_time(const struct os_reltime *fetch_time,
+ unsigned int age_ms,
+ struct os_reltime *update_time)
{
os_time_t usec;
+ update_time->sec = fetch_time->sec;
+ update_time->usec = fetch_time->usec;
+ update_time->sec -= age_ms / 1000;
+ usec = (age_ms % 1000) * 1000;
+ if (update_time->usec < usec) {
+ update_time->sec--;
+ update_time->usec += 1000000;
+ }
+ update_time->usec -= usec;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+ struct os_reltime *fetch_time)
+{
dst->flags = src->flags;
os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
dst->freq = src->freq;
@@ -91,14 +255,7 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
dst->level = src->level;
dst->tsf = src->tsf;
- os_get_time(&dst->last_update);
- dst->last_update.sec -= src->age / 1000;
- usec = (src->age % 1000) * 1000;
- if (dst->last_update.usec < usec) {
- dst->last_update.sec--;
- dst->last_update.usec += 1000000;
- }
- dst->last_update.usec -= usec;
+ calculate_update_time(fetch_time, src->age, &dst->last_update);
}
@@ -118,13 +275,21 @@ static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
}
+static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ return bss == wpa_s->current_bss ||
+ os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+ os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+}
+
+
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)) {
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, __func__);
return 0;
}
}
@@ -133,41 +298,58 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
}
-static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
{
+ struct wpa_bss *bss;
+
/*
* Remove the oldest entry that does not match with any configured
* network.
*/
if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
- return;
+ return 0;
/*
- * Remove the oldest entry since no better candidate for removal was
- * found.
+ * Remove the oldest entry that isn't currently in use.
*/
- wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
- struct wpa_bss, list));
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (!wpa_bss_in_use(wpa_s, bss)) {
+ wpa_bss_remove(wpa_s, bss, __func__);
+ return 0;
+ }
+ }
+
+ return -1;
}
-static void wpa_bss_add(struct wpa_supplicant *wpa_s,
- const u8 *ssid, size_t ssid_len,
- struct wpa_scan_res *res)
+static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len,
+ struct wpa_scan_res *res,
+ struct os_reltime *fetch_time)
{
struct wpa_bss *bss;
bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
if (bss == NULL)
- return;
+ return NULL;
bss->id = wpa_s->bss_next_id++;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
os_memcpy(bss->ssid, ssid, ssid_len);
bss->ssid_len = ssid_len;
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ wpa_bss_set_hessid(bss);
+
+ if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
+ wpa_bss_remove_oldest(wpa_s) != 0) {
+ wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+ "because all BSSes are in use. We should normally "
+ "not get here!", (int) wpa_s->num_bss + 1);
+ wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
+ }
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
@@ -176,8 +358,7 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s,
" SSID '%s'",
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
- if (wpa_s->num_bss > wpa_s->conf->bss_max_count)
- wpa_bss_remove_oldest(wpa_s);
+ return bss;
}
@@ -309,17 +490,34 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
}
-static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- struct wpa_scan_res *res)
+static struct wpa_bss *
+wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_scan_res *res, struct os_reltime *fetch_time)
{
u32 changes;
changes = wpa_bss_compare_res(bss, res);
bss->scan_miss_count = 0;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
/* Move the entry to the end of the list */
dl_list_del(&bss->list);
+#ifdef CONFIG_P2P
+ if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
+ /*
+ * This can happen when non-P2P station interface runs a scan
+ * without P2P IE in the Probe Request frame. P2P GO would reply
+ * to that with a Probe Response that does not include P2P IE.
+ * Do not update the IEs in this BSS entry to avoid such loss of
+ * information that may be needed for P2P operations to
+ * determine group information.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
+ MACSTR " since that would remove P2P IE information",
+ MAC2STR(bss->bssid));
+ } else
+#endif /* CONFIG_P2P */
if (bss->ie_len + bss->beacon_ie_len >=
res->ie_len + res->beacon_ie_len) {
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
@@ -332,6 +530,13 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
res->beacon_ie_len);
if (nbss) {
+ unsigned int i;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (wpa_s->last_scan_res[i] == bss) {
+ wpa_s->last_scan_res[i] = nbss;
+ break;
+ }
+ }
if (wpa_s->current_bss == bss)
wpa_s->current_bss = nbss;
bss = nbss;
@@ -342,34 +547,67 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
dl_list_add(prev, &bss->list_id);
}
+ if (changes & WPA_BSS_IES_CHANGED_FLAG)
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
notify_bss_changes(wpa_s, changes, bss);
-}
-
-static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-{
- return bss == wpa_s->current_bss ||
- os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
- os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+ return bss;
}
+/**
+ * wpa_bss_update_start - Start a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is called at the start of each BSS table update round for new
+ * scan results. The actual scan result entries are indicated with calls to
+ * wpa_bss_update_scan_res() and the update round is finished with a call to
+ * wpa_bss_update_end().
+ */
void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
{
wpa_s->bss_update_idx++;
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
wpa_s->bss_update_idx);
+ wpa_s->last_scan_res_used = 0;
}
+/**
+ * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @res: Scan result
+ * @fetch_time: Time when the result was fetched from the driver
+ *
+ * This function updates a BSS table entry (or adds one) based on a scan result.
+ * This is called separately for each scan result between the calls to
+ * wpa_bss_update_start() and wpa_bss_update_end().
+ */
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_reltime *fetch_time)
{
const u8 *ssid, *p2p;
struct wpa_bss *bss;
+ if (wpa_s->conf->ignore_old_scan_res) {
+ struct os_reltime update;
+ calculate_update_time(fetch_time, res->age, &update);
+ if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
+ struct os_reltime age;
+ os_reltime_sub(&wpa_s->scan_trigger_time, &update,
+ &age);
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
+ "table entry that is %u.%06u seconds older "
+ "than our scan trigger",
+ (unsigned int) age.sec,
+ (unsigned int) age.usec);
+ return;
+ }
+ }
+
ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
if (ssid == NULL) {
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
@@ -383,6 +621,18 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
}
p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
+#ifdef CONFIG_P2P
+ if (p2p == NULL &&
+ wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ /*
+ * If it's a P2P specific interface, then don't update
+ * the scan result without a P2P IE.
+ */
+ wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
+ " update for P2P interface", MAC2STR(res->bssid));
+ return;
+ }
+#endif /* CONFIG_P2P */
if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
return; /* Skip P2P listen discovery results here */
@@ -391,9 +641,38 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
* (to save memory) */
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
if (bss == NULL)
- wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
- else
- wpa_bss_update(wpa_s, bss, res);
+ bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
+ else {
+ bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
+ if (wpa_s->last_scan_res) {
+ unsigned int i;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (bss == wpa_s->last_scan_res[i]) {
+ /* Already in the list */
+ return;
+ }
+ }
+ }
+ }
+
+ if (bss == NULL)
+ return;
+ if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
+ struct wpa_bss **n;
+ unsigned int siz;
+ if (wpa_s->last_scan_res_size == 0)
+ siz = 32;
+ else
+ siz = wpa_s->last_scan_res_size * 2;
+ n = os_realloc_array(wpa_s->last_scan_res, siz,
+ sizeof(struct wpa_bss *));
+ if (n == NULL)
+ return;
+ wpa_s->last_scan_res = n;
+ wpa_s->last_scan_res_size = siz;
+ }
+
+ wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
}
@@ -438,11 +717,22 @@ static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
}
+/**
+ * wpa_bss_update_end - End a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about scan parameters
+ * @new_scan: Whether this update round was based on a new scan
+ *
+ * This function is called at the end of each BSS table update round for new
+ * scan results. The start of the update was indicated with a call to
+ * wpa_bss_update_start().
+ */
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan)
{
struct wpa_bss *bss, *n;
+ os_get_reltime(&wpa_s->last_scan);
if (!new_scan)
return; /* do not expire entries without new scan */
@@ -455,33 +745,39 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
bss->scan_miss_count++;
if (bss->scan_miss_count >=
wpa_s->conf->bss_expiration_scan_count) {
- wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
- "no match in scan", bss->id);
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, "no match in scan");
}
}
+
+ wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+ wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
}
+/**
+ * wpa_bss_flush_by_age - Flush old BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @age: Maximum entry age in seconds
+ *
+ * Remove BSS entries that have not been updated during the last @age seconds.
+ */
void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
{
struct wpa_bss *bss, *n;
- struct os_time t;
+ struct os_reltime t;
if (dl_list_empty(&wpa_s->bss))
return;
- os_get_time(&t);
+ os_get_reltime(&t);
t.sec -= age;
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
- if (os_time_before(&bss->last_update, &t)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
- "age", bss->id);
- wpa_bss_remove(wpa_s, bss);
+ if (os_reltime_before(&bss->last_update, &t)) {
+ wpa_bss_remove(wpa_s, bss, __func__);
} else
break;
}
@@ -498,6 +794,14 @@ static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
}
+/**
+ * wpa_bss_init - Initialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This prepares BSS table lists and timer for periodic updates. The BSS table
+ * is deinitialized with wpa_bss_deinit() once not needed anymore.
+ */
int wpa_bss_init(struct wpa_supplicant *wpa_s)
{
dl_list_init(&wpa_s->bss);
@@ -508,21 +812,31 @@ int wpa_bss_init(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpa_bss_flush - Flush all unused BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
void wpa_bss_flush(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss, *n;
+ wpa_s->clear_driver_scan_cache = 1;
+
if (wpa_s->bss.next == NULL)
return; /* BSS table not yet initialized */
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, __func__);
}
}
+/**
+ * wpa_bss_deinit - Deinitialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
@@ -530,10 +844,18 @@ void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid)
{
struct wpa_bss *bss;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
return bss;
@@ -542,7 +864,41 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
+ * find the entry that has the most recent update. This can help in finding the
+ * correct entry in cases where the SSID of the AP may have changed recently
+ * (e.g., in WPS reconfiguration cases).
+ */
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bss *bss, *found = NULL;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
+ continue;
+ if (found == NULL ||
+ os_reltime_before(&found->last_update, &bss->last_update))
+ found = bss;
+ }
+ return found;
+}
+
+
#ifdef CONFIG_P2P
+/**
+ * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dev_addr: P2P Device Address of the GO
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr)
{
@@ -559,6 +915,12 @@ struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_P2P */
+/**
+ * wpa_bss_get_id - Fetch a BSS table entry based on identifier
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
{
struct wpa_bss *bss;
@@ -570,6 +932,38 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
}
+/**
+ * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @idf: Smallest allowed identifier assigned for the entry
+ * @idf: Largest allowed identifier assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
+ * smallest id value to be fetched within the specified range without the
+ * caller having to know the exact id.
+ */
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl)
+{
+ struct wpa_bss *bss;
+ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+ if (bss->id >= idf && bss->id <= idl)
+ return bss;
+ }
+ return NULL;
+}
+
+
+/**
+ * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
const u8 *end, *pos;
@@ -589,6 +983,15 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
}
+/**
+ * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
{
const u8 *end, *pos;
@@ -609,6 +1012,53 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
}
+/**
+ * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ *
+ * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+ u32 vendor_type)
+{
+ const u8 *end, *pos;
+
+ if (bss->beacon_ie_len == 0)
+ return NULL;
+
+ pos = (const u8 *) (bss + 1);
+ pos += bss->ie_len;
+ end = pos + bss->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ */
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type)
{
@@ -640,6 +1090,56 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
}
+/**
+ * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ *
+ * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+ u32 vendor_type)
+{
+ struct wpabuf *buf;
+ const u8 *end, *pos;
+
+ buf = wpabuf_alloc(bss->beacon_ie_len);
+ if (buf == NULL)
+ return NULL;
+
+ pos = (const u8 *) (bss + 1);
+ pos += bss->ie_len;
+ end = pos + bss->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+ pos += 2 + pos[1];
+ }
+
+ if (wpabuf_len(buf) == 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+
+/**
+ * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
+ * @bss: BSS table entry
+ * Returns: Maximum legacy rate in units of 500 kbps
+ */
int wpa_bss_get_max_rate(const struct wpa_bss *bss)
{
int rate = 0;
@@ -662,6 +1162,15 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss)
}
+/**
+ * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
+ * @bss: BSS table entry
+ * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
+ * Returns: number of legacy TX rates or -1 on failure
+ *
+ * The caller is responsible for freeing the returned buffer with os_free() in
+ * case of success.
+ */
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
{
const u8 *ie, *ie2;
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 9f13298..4deeb5f 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -2,14 +2,8 @@
* BSS table
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BSS_H
@@ -26,56 +20,76 @@ struct wpa_scan_res;
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
/**
+ * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
+ */
+struct wpa_bss_anqp {
+ /** Number of BSS entries referring to this ANQP data instance */
+ unsigned int users;
+#ifdef CONFIG_INTERWORKING
+ struct wpabuf *venue_name;
+ struct wpabuf *network_auth_type;
+ struct wpabuf *roaming_consortium;
+ struct wpabuf *ip_addr_type_availability;
+ struct wpabuf *nai_realm;
+ struct wpabuf *anqp_3gpp;
+ struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ struct wpabuf *hs20_operator_friendly_name;
+ struct wpabuf *hs20_wan_metrics;
+ struct wpabuf *hs20_connection_capability;
+ struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
+
+/**
* struct wpa_bss - BSS table
- * @list: List entry for struct wpa_supplicant::bss
- * @list_id: List entry for struct wpa_supplicant::bss_id
- * @id: Unique identifier for this BSS entry
- * @scan_miss_count: Number of counts without seeing this BSS
- * @flags: information flags about the BSS/IBSS (WPA_BSS_*)
- * @last_update_idx: Index of the last scan update
- * @bssid: BSSID
- * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
- * @beacon_int: beacon interval in TUs (host byte order)
- * @caps: capability information field in host byte order
- * @qual: signal quality
- * @noise: noise level
- * @level: signal level
- * @tsf: Timestamp of last Beacon/Probe Response frame
- * @last_update: Time of the last update (i.e., Beacon or Probe Response RX)
- * @ie_len: length of the following IE field in octets (from Probe Response)
- * @beacon_ie_len: length of the following Beacon IE field in octets
*
* This structure is used to store information about neighboring BSSes in
* generic format. It is mainly updated based on scan results from the driver.
*/
struct wpa_bss {
+ /** List entry for struct wpa_supplicant::bss */
struct dl_list list;
+ /** List entry for struct wpa_supplicant::bss_id */
struct dl_list list_id;
+ /** Unique identifier for this BSS entry */
unsigned int id;
+ /** Number of counts without seeing this BSS */
unsigned int scan_miss_count;
+ /** Index of the last scan update */
unsigned int last_update_idx;
+ /** Information flags about the BSS/IBSS (WPA_BSS_*) */
unsigned int flags;
+ /** BSSID */
u8 bssid[ETH_ALEN];
+ /** HESSID */
+ u8 hessid[ETH_ALEN];
+ /** SSID */
u8 ssid[32];
+ /** Length of SSID */
size_t ssid_len;
+ /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
int freq;
+ /** Beacon interval in TUs (host byte order) */
u16 beacon_int;
+ /** Capability information field in host byte order */
u16 caps;
+ /** Signal quality */
int qual;
+ /** Noise level */
int noise;
+ /** Signal level */
int level;
+ /** Timestamp of last Beacon/Probe Response frame */
u64 tsf;
- struct os_time last_update;
-#ifdef CONFIG_INTERWORKING
- struct wpabuf *anqp_venue_name;
- struct wpabuf *anqp_network_auth_type;
- struct wpabuf *anqp_roaming_consortium;
- struct wpabuf *anqp_ip_addr_type_availability;
- struct wpabuf *anqp_nai_realm;
- struct wpabuf *anqp_3gpp;
- struct wpabuf *anqp_domain_name;
-#endif /* CONFIG_INTERWORKING */
+ /** Time of the last update (i.e., Beacon or Probe Response RX) */
+ struct os_reltime last_update;
+ /** ANQP data */
+ struct wpa_bss_anqp *anqp;
+ /** Length of the following IE field in octets (from Probe Response) */
size_t ie_len;
+ /** Length of the following Beacon IE field in octets */
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
/* followed by beacon_ie_len octets of IEs */
@@ -83,7 +97,8 @@ struct wpa_bss {
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 wpa_scan_res *res,
+ struct os_reltime *fetch_time);
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);
@@ -94,14 +109,24 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len);
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+ u32 vendor_type);
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type);
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+ u32 vendor_type);
int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
#endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 8c09894..2dd7054 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,21 +1,16 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "utils/uuid.h"
+#include "utils/ip_addr.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -59,42 +54,6 @@ struct parse_data {
};
-static char * wpa_config_parse_string(const char *value, size_t *len)
-{
- if (*value == '"') {
- const char *pos;
- char *str;
- value++;
- pos = os_strrchr(value, '"');
- if (pos == NULL || pos[1] != '\0')
- return NULL;
- *len = pos - value;
- str = os_malloc(*len + 1);
- if (str == NULL)
- return NULL;
- os_memcpy(str, value, *len);
- str[*len] = '\0';
- return str;
- } else {
- u8 *str;
- size_t tlen, hlen = os_strlen(value);
- if (hlen & 1)
- return NULL;
- tlen = hlen / 2;
- str = os_malloc(tlen + 1);
- if (str == NULL)
- return NULL;
- if (hexstr2bin(value, str, tlen)) {
- os_free(str);
- return NULL;
- }
- str[tlen] = '\0';
- *len = tlen;
- return (char *) str;
- }
-}
-
-
static int wpa_config_parse_str(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
@@ -155,18 +114,6 @@ set:
#ifndef NO_CONFIG_WRITE
-static int is_hex(const u8 *data, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (data[i] < 32 || data[i] >= 127)
- return 1;
- }
- return 0;
-}
-
-
static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
{
char *buf;
@@ -232,10 +179,17 @@ static int wpa_config_parse_int(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
{
- int *dst;
+ int val, *dst;
+ char *end;
dst = (int *) (((u8 *) ssid) + (long) data->param1);
- *dst = atoi(value);
+ val = strtol(value, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, value);
+ return -1;
+ }
+ *dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
if (data->param3 && *dst < (long) data->param3) {
@@ -330,6 +284,21 @@ static int wpa_config_parse_psk(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ os_free(ssid->passphrase);
+ ssid->passphrase = NULL;
+ ssid->psk_set = 0;
+ os_free(ssid->ext_psk);
+ ssid->ext_psk = os_strdup(value + 4);
+ if (ssid->ext_psk == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+ ssid->ext_psk);
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (*value == '"') {
#ifndef CONFIG_NO_PBKDF2
const char *pos;
@@ -354,11 +323,9 @@ static int wpa_config_parse_psk(const struct parse_data *data,
return 0;
ssid->psk_set = 0;
os_free(ssid->passphrase);
- ssid->passphrase = os_malloc(len + 1);
+ ssid->passphrase = dup_binstr(value, len);
if (ssid->passphrase == NULL)
return -1;
- os_memcpy(ssid->passphrase, value, len);
- ssid->passphrase[len] = '\0';
return 0;
#else /* CONFIG_NO_PBKDF2 */
wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
@@ -387,6 +354,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
static char * wpa_config_write_psk(const struct parse_data *data,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+ char *buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (ssid->passphrase)
return wpa_config_write_string_ascii(
(const u8 *) ssid->passphrase,
@@ -532,6 +510,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ else if (os_strcmp(start, "SAE") == 0)
+ val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "FT-SAE") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -563,10 +547,10 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
char *buf, *pos, *end;
int ret;
- pos = buf = os_zalloc(50);
+ pos = buf = os_zalloc(100);
if (buf == NULL)
return NULL;
- end = buf + 50;
+ end = buf + 100;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
@@ -619,101 +603,8 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
}
#ifdef CONFIG_IEEE80211R
- if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
- pos += os_snprintf(pos, end - pos, "%sFT-PSK",
- pos == buf ? "" : " ");
-
- if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
- pos += os_snprintf(pos, end - pos, "%sFT-EAP",
- pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211W
- if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
- pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
- pos == buf ? "" : " ");
-
- if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
- pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
- pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_WPS
- if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
- pos += os_snprintf(pos, end - pos, "%sWPS",
- pos == buf ? "" : " ");
-#endif /* CONFIG_WPS */
-
- return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_cipher(int line, const char *value)
-{
- int val = 0, last;
- char *start, *end, *buf;
-
- buf = os_strdup(value);
- if (buf == NULL)
- return -1;
- start = buf;
-
- while (*start != '\0') {
- while (*start == ' ' || *start == '\t')
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (*end != ' ' && *end != '\t' && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
- if (os_strcmp(start, "CCMP") == 0)
- val |= WPA_CIPHER_CCMP;
- else if (os_strcmp(start, "TKIP") == 0)
- val |= WPA_CIPHER_TKIP;
- else if (os_strcmp(start, "WEP104") == 0)
- val |= WPA_CIPHER_WEP104;
- else if (os_strcmp(start, "WEP40") == 0)
- val |= WPA_CIPHER_WEP40;
- else if (os_strcmp(start, "NONE") == 0)
- val |= WPA_CIPHER_NONE;
- else {
- wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
- line, start);
- os_free(buf);
- return -1;
- }
-
- if (last)
- break;
- start = end + 1;
- }
- os_free(buf);
-
- if (val == 0) {
- wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
- line);
- return -1;
- }
- return val;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_cipher(int cipher)
-{
- char *buf, *pos, *end;
- int ret;
-
- pos = buf = os_zalloc(50);
- if (buf == NULL)
- return NULL;
- end = buf + 50;
-
- if (cipher & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP",
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+ ret = os_snprintf(pos, end - pos, "%sFT-PSK",
pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
@@ -722,8 +613,8 @@ static char * wpa_config_write_cipher(int cipher)
pos += ret;
}
- if (cipher & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP",
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+ ret = os_snprintf(pos, end - pos, "%sFT-EAP",
pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
@@ -731,9 +622,11 @@ static char * wpa_config_write_cipher(int cipher)
}
pos += ret;
}
+#endif /* CONFIG_IEEE80211R */
- if (cipher & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
+#ifdef CONFIG_IEEE80211W
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
@@ -742,8 +635,8 @@ static char * wpa_config_write_cipher(int cipher)
pos += ret;
}
- if (cipher & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40",
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
@@ -751,9 +644,11 @@ static char * wpa_config_write_cipher(int cipher)
}
pos += ret;
}
+#endif /* CONFIG_IEEE80211W */
- if (cipher & WPA_CIPHER_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE",
+#ifdef CONFIG_WPS
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ ret = os_snprintf(pos, end - pos, "%sWPS",
pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
@@ -761,6 +656,41 @@ static char * wpa_config_write_cipher(int cipher)
}
pos += ret;
}
+#endif /* CONFIG_WPS */
+
+ return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+ int val = wpa_parse_cipher(value);
+ if (val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, value);
+ return -1;
+ }
+ if (val == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+ line);
+ return -1;
+ }
+ return val;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_cipher(int cipher)
+{
+ char *buf = os_zalloc(50);
+ if (buf == NULL)
+ return NULL;
+
+ if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
+ os_free(buf);
+ return NULL;
+ }
return buf;
}
@@ -775,7 +705,7 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+ if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) {
wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
"(0x%x).", line, val);
return -1;
@@ -804,8 +734,7 @@ static int wpa_config_parse_group(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
- WPA_CIPHER_WEP40)) {
+ if (val & ~WPA_ALLOWED_GROUP_CIPHERS) {
wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
"(0x%x).", line, val);
return -1;
@@ -925,9 +854,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
-static int * wpa_config_parse_freqs(const struct parse_data *data,
- struct wpa_ssid *ssid, int line,
- const char *value)
+static int * wpa_config_parse_int_array(const char *value)
{
int *freqs;
size_t used, len;
@@ -935,7 +862,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
used = 0;
len = 10;
- freqs = os_zalloc((len + 1) * sizeof(int));
+ freqs = os_calloc(len + 1, sizeof(int));
if (freqs == NULL)
return NULL;
@@ -946,7 +873,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
if (used == len) {
int *n;
size_t i;
- n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
+ n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
if (n == NULL) {
os_free(freqs);
return NULL;
@@ -974,9 +901,13 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data,
{
int *freqs;
- freqs = wpa_config_parse_freqs(data, ssid, line, value);
+ freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(ssid->scan_freq);
ssid->scan_freq = freqs;
@@ -990,9 +921,13 @@ static int wpa_config_parse_freq_list(const struct parse_data *data,
{
int *freqs;
- freqs = wpa_config_parse_freqs(data, ssid, line, value);
+ freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(ssid->freq_list);
ssid->freq_list = freqs;
@@ -1075,8 +1010,8 @@ static int wpa_config_parse_eap(const struct parse_data *data,
last = *end == '\0';
*end = '\0';
tmp = methods;
- methods = os_realloc(methods,
- (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1,
+ sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
os_free(buf);
@@ -1106,7 +1041,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
os_free(buf);
tmp = methods;
- methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
return -1;
@@ -1172,6 +1107,20 @@ static int wpa_config_parse_password(const struct parse_data *data,
return 0;
}
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+ if (name == NULL)
+ return -1;
+ os_free(ssid->eap.password);
+ ssid->eap.password = (u8 *) name;
+ ssid->eap.password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (os_strncmp(value, "hash:", 5) != 0) {
char *tmp;
size_t res_len;
@@ -1189,6 +1138,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
ssid->eap.password = (u8 *) tmp;
ssid->eap.password_len = res_len;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1217,6 +1167,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
ssid->eap.password = hash;
ssid->eap.password_len = 16;
ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1230,6 +1181,17 @@ static char * wpa_config_write_password(const struct parse_data *data,
if (ssid->eap.password == NULL)
return NULL;
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.password_len + 1);
+ if (buf == NULL)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
return wpa_config_write_string(
ssid->eap.password, ssid->eap.password_len);
@@ -1265,6 +1227,11 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
os_free(buf);
return -1;
}
+ if (*len && *len != 5 && *len != 13 && *len != 16) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+ "this network block will be ignored",
+ line, (unsigned int) *len);
+ }
os_memcpy(key, buf, *len);
os_free(buf);
res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
@@ -1355,6 +1322,52 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
#ifdef CONFIG_P2P
+static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+ os_strcmp(value, "any") == 0) {
+ os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN);
+ wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any");
+ return 0;
+ }
+ if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->bssid_set = 1;
+ wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR,
+ MAC2STR(ssid->go_p2p_dev_addr));
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value;
+ int res;
+
+ if (is_zero_ether_addr(ssid->go_p2p_dev_addr))
+ return NULL;
+
+ value = os_malloc(20);
+ if (value == NULL)
+ return NULL;
+ res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
+ if (res < 0 || res >= 20) {
+ os_free(value);
+ return NULL;
+ }
+ value[20 - 1] = '\0';
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -1385,7 +1398,7 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
"truncated p2p_client_list address '%s'",
line, pos);
} else {
- n = os_realloc(buf, (count + 1) * ETH_ALEN);
+ n = os_realloc_array(buf, count + 1, ETH_ALEN);
if (n == NULL) {
os_free(buf);
return -1;
@@ -1444,6 +1457,60 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
}
#endif /* NO_CONFIG_WRITE */
+
+static int wpa_config_parse_psk_list(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ struct psk_list_entry *p;
+ const char *pos;
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return -1;
+
+ pos = value;
+ if (os_strncmp(pos, "P2P-", 4) == 0) {
+ p->p2p = 1;
+ pos += 4;
+ }
+
+ if (hwaddr_aton(pos, p->addr)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'",
+ line, pos);
+ os_free(p);
+ return -1;
+ }
+ pos += 17;
+ if (*pos != '-') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'",
+ line, pos);
+ os_free(p);
+ return -1;
+ }
+ pos++;
+
+ if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'",
+ line, pos);
+ os_free(p);
+ return -1;
+ }
+
+ dl_list_add(&ssid->psk_list, &p->list);
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_psk_list(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
#endif /* CONFIG_P2P */
/* Helper macros for network block parser */
@@ -1540,6 +1607,7 @@ static const struct parse_data ssid_fields[] = {
{ FUNC_KEY(psk) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
+ { INT(bg_scan_period) },
{ FUNC(pairwise) },
{ FUNC(group) },
{ FUNC(auth_alg) },
@@ -1558,6 +1626,7 @@ static const struct parse_data ssid_fields[] = {
{ STRe(dh_file) },
{ STRe(subject_match) },
{ STRe(altsubject_match) },
+ { STRe(domain_suffix_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
@@ -1566,6 +1635,7 @@ static const struct parse_data ssid_fields[] = {
{ STRe(dh_file2) },
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
+ { STRe(domain_suffix_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
@@ -1593,6 +1663,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(eap_workaround) },
{ STRe(pac_file) },
{ INTe(fragment_size) },
+ { INTe(ocsp) },
#endif /* IEEE8021X_EAPOL */
{ INT_RANGE(mode, 0, 4) },
{ INT_RANGE(proactive_key_caching, 0, 1) },
@@ -1603,12 +1674,48 @@ static const struct parse_data ssid_fields[] = {
#endif /* CONFIG_IEEE80211W */
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
- { INT_RANGE(frequency, 0, 10000) },
+ { INT_RANGE(frequency, 0, 65000) },
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
+ { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
+ { FUNC(go_p2p_dev_addr) },
{ FUNC(p2p_client_list) },
+ { FUNC(psk_list) },
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HT_OVERRIDES
+ { INT_RANGE(disable_ht, 0, 1) },
+ { INT_RANGE(disable_ht40, -1, 1) },
+ { INT_RANGE(disable_sgi, 0, 1) },
+ { INT_RANGE(disable_max_amsdu, -1, 1) },
+ { INT_RANGE(ampdu_factor, -1, 3) },
+ { INT_RANGE(ampdu_density, -1, 7) },
+ { STR(ht_mcs) },
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ { INT_RANGE(disable_vht, 0, 1) },
+ { INT(vht_capa) },
+ { INT(vht_capa_mask) },
+ { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
+#endif /* CONFIG_VHT_OVERRIDES */
+ { INT(ap_max_inactivity) },
+ { INT(dtim_period) },
+ { INT(beacon_int) },
};
#undef OFFSET
@@ -1627,7 +1734,7 @@ static const struct parse_data ssid_fields[] = {
#undef _FUNC
#undef FUNC
#undef FUNC_KEY
-#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
/**
@@ -1662,19 +1769,20 @@ int wpa_config_add_prio_network(struct wpa_config *config,
}
/* First network for this priority - add a new priority list */
- nlist = os_realloc(config->pssid,
- (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ nlist = os_realloc_array(config->pssid, config->num_prio + 1,
+ sizeof(struct wpa_ssid *));
if (nlist == NULL)
return -1;
for (prio = 0; prio < config->num_prio; prio++) {
- if (nlist[prio]->priority < ssid->priority)
+ if (nlist[prio]->priority < ssid->priority) {
+ os_memmove(&nlist[prio + 1], &nlist[prio],
+ (config->num_prio - prio) *
+ sizeof(struct wpa_ssid *));
break;
+ }
}
- os_memmove(&nlist[prio + 1], &nlist[prio],
- (config->num_prio - prio) * sizeof(struct wpa_ssid *));
-
nlist[prio] = ssid;
config->num_prio++;
config->pssid = nlist;
@@ -1728,6 +1836,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->dh_file);
os_free(eap->subject_match);
os_free(eap->altsubject_match);
+ os_free(eap->domain_suffix_match);
os_free(eap->ca_cert2);
os_free(eap->ca_path2);
os_free(eap->client_cert2);
@@ -1736,6 +1845,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->dh_file2);
os_free(eap->subject_match2);
os_free(eap->altsubject_match2);
+ os_free(eap->domain_suffix_match2);
os_free(eap->phase1);
os_free(eap->phase2);
os_free(eap->pcsc);
@@ -1753,6 +1863,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
os_free(eap->new_password);
+ os_free(eap->external_sim_resp);
}
#endif /* IEEE8021X_EAPOL */
@@ -1766,8 +1877,11 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
*/
void wpa_config_free_ssid(struct wpa_ssid *ssid)
{
+ struct psk_list_entry *psk;
+
os_free(ssid->ssid);
os_free(ssid->passphrase);
+ os_free(ssid->ext_psk);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
#endif /* IEEE8021X_EAPOL */
@@ -1776,10 +1890,59 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
+#ifdef CONFIG_HT_OVERRIDES
+ os_free(ssid->ht_mcs);
+#endif /* CONFIG_HT_OVERRIDES */
+ while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
+ list))) {
+ dl_list_del(&psk->list);
+ os_free(psk);
+ }
os_free(ssid);
}
+void wpa_config_free_cred(struct wpa_cred *cred)
+{
+ size_t i;
+
+ os_free(cred->realm);
+ os_free(cred->username);
+ os_free(cred->password);
+ os_free(cred->ca_cert);
+ os_free(cred->client_cert);
+ os_free(cred->private_key);
+ os_free(cred->private_key_passwd);
+ os_free(cred->imsi);
+ os_free(cred->milenage);
+ for (i = 0; i < cred->num_domain; i++)
+ os_free(cred->domain[i]);
+ os_free(cred->domain);
+ os_free(cred->domain_suffix_match);
+ os_free(cred->eap_method);
+ os_free(cred->phase1);
+ os_free(cred->phase2);
+ os_free(cred->excluded_ssid);
+ os_free(cred);
+}
+
+
+void wpa_config_flush_blobs(struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+ struct wpa_config_blob *blob, *prev;
+
+ blob = config->blobs;
+ config->blobs = NULL;
+ while (blob) {
+ prev = blob;
+ blob = blob->next;
+ wpa_config_free_blob(prev);
+ }
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
/**
* wpa_config_free - Free configuration data
* @config: Configuration data from wpa_config_read()
@@ -1789,10 +1952,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
*/
void wpa_config_free(struct wpa_config *config)
{
-#ifndef CONFIG_NO_CONFIG_BLOBS
- struct wpa_config_blob *blob, *prevblob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
struct wpa_ssid *ssid, *prev = NULL;
+ struct wpa_cred *cred, *cprev;
ssid = config->ssid;
while (ssid) {
@@ -1801,21 +1962,23 @@ void wpa_config_free(struct wpa_config *config)
wpa_config_free_ssid(prev);
}
-#ifndef CONFIG_NO_CONFIG_BLOBS
- blob = config->blobs;
- prevblob = NULL;
- while (blob) {
- prevblob = blob;
- blob = blob->next;
- wpa_config_free_blob(prevblob);
+ cred = config->cred;
+ while (cred) {
+ cprev = cred;
+ cred = cred->next;
+ wpa_config_free_cred(cprev);
}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
+ wpa_config_flush_blobs(config);
+
+ wpabuf_free(config->wps_vendor_ext_m1);
os_free(config->ctrl_interface);
os_free(config->ctrl_interface_group);
os_free(config->opensc_engine_path);
os_free(config->pkcs11_engine_path);
os_free(config->pkcs11_module_path);
+ os_free(config->pcsc_reader);
+ os_free(config->pcsc_pin);
os_free(config->driver_param);
os_free(config->device_name);
os_free(config->manufacturer);
@@ -1825,13 +1988,16 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->config_methods);
os_free(config->p2p_ssid_postfix);
os_free(config->pssid);
- os_free(config->home_realm);
- os_free(config->home_username);
- os_free(config->home_password);
- os_free(config->home_ca_cert);
- os_free(config->home_imsi);
- os_free(config->home_milenage);
os_free(config->p2p_pref_chan);
+ os_free(config->p2p_no_go_freq.range);
+ os_free(config->autoscan);
+ os_free(config->freq_list);
+ wpabuf_free(config->wps_nfc_dh_pubkey);
+ wpabuf_free(config->wps_nfc_dh_privkey);
+ wpabuf_free(config->wps_nfc_dev_pw);
+ os_free(config->ext_password_backend);
+ os_free(config->sae_groups);
+ wpabuf_free(config->ap_vendor_elements);
os_free(config);
}
@@ -1906,6 +2072,7 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
if (ssid == NULL)
return NULL;
ssid->id = id;
+ dl_list_init(&ssid->psk_list);
if (last)
last->next = ssid;
else
@@ -1959,11 +2126,42 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_HT_OVERRIDES
+ ssid->disable_ht = DEFAULT_DISABLE_HT;
+ ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
+ ssid->disable_sgi = DEFAULT_DISABLE_SGI;
+ ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
+ ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
+ ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ ssid->vht_rx_mcs_nss_1 = -1;
+ ssid->vht_rx_mcs_nss_2 = -1;
+ ssid->vht_rx_mcs_nss_3 = -1;
+ ssid->vht_rx_mcs_nss_4 = -1;
+ ssid->vht_rx_mcs_nss_5 = -1;
+ ssid->vht_rx_mcs_nss_6 = -1;
+ ssid->vht_rx_mcs_nss_7 = -1;
+ ssid->vht_rx_mcs_nss_8 = -1;
+ ssid->vht_tx_mcs_nss_1 = -1;
+ ssid->vht_tx_mcs_nss_2 = -1;
+ ssid->vht_tx_mcs_nss_3 = -1;
+ ssid->vht_tx_mcs_nss_4 = -1;
+ ssid->vht_tx_mcs_nss_5 = -1;
+ ssid->vht_tx_mcs_nss_6 = -1;
+ ssid->vht_tx_mcs_nss_7 = -1;
+ ssid->vht_tx_mcs_nss_8 = -1;
+#endif /* CONFIG_VHT_OVERRIDES */
+ ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
}
@@ -2058,7 +2256,7 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
get_keys = get_keys && ssid->export_keys;
- props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
+ props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
if (!props)
return NULL;
@@ -2186,8 +2384,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
void wpa_config_update_psk(struct wpa_ssid *ssid)
{
#ifndef CONFIG_NO_PBKDF2
- pbkdf2_sha1(ssid->passphrase,
- (char *) ssid->ssid, ssid->ssid_len, 4096,
+ pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
ssid->psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
ssid->psk, PMK_LEN);
@@ -2196,6 +2393,282 @@ void wpa_config_update_psk(struct wpa_ssid *ssid)
}
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+ const char *value, int line)
+{
+ char *val;
+ size_t len;
+
+ if (os_strcmp(var, "temporary") == 0) {
+ cred->temporary = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "priority") == 0) {
+ cred->priority = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "pcsc") == 0) {
+ cred->pcsc = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "eap") == 0) {
+ struct eap_method_type method;
+ method.method = eap_peer_get_type(value, &method.vendor);
+ if (method.vendor == EAP_VENDOR_IETF &&
+ method.method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+ "for a credential", line, value);
+ return -1;
+ }
+ os_free(cred->eap_method);
+ cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+ if (cred->eap_method == NULL)
+ return -1;
+ os_memcpy(cred->eap_method, &method, sizeof(method));
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0 &&
+ os_strncmp(value, "ext:", 4) == 0) {
+ os_free(cred->password);
+ cred->password = os_strdup(value);
+ cred->ext_password = 1;
+ return 0;
+ }
+
+ val = wpa_config_parse_string(value, &len);
+ if (val == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+ "value '%s'.", line, var, value);
+ return -1;
+ }
+
+ if (os_strcmp(var, "realm") == 0) {
+ os_free(cred->realm);
+ cred->realm = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "username") == 0) {
+ os_free(cred->username);
+ cred->username = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0) {
+ os_free(cred->password);
+ cred->password = val;
+ cred->ext_password = 0;
+ return 0;
+ }
+
+ if (os_strcmp(var, "ca_cert") == 0) {
+ os_free(cred->ca_cert);
+ cred->ca_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "client_cert") == 0) {
+ os_free(cred->client_cert);
+ cred->client_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "private_key") == 0) {
+ os_free(cred->private_key);
+ cred->private_key = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "private_key_passwd") == 0) {
+ os_free(cred->private_key_passwd);
+ cred->private_key_passwd = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "imsi") == 0) {
+ os_free(cred->imsi);
+ cred->imsi = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "milenage") == 0) {
+ os_free(cred->milenage);
+ cred->milenage = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "domain_suffix_match") == 0) {
+ os_free(cred->domain_suffix_match);
+ cred->domain_suffix_match = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "domain") == 0) {
+ char **new_domain;
+ new_domain = os_realloc_array(cred->domain,
+ cred->num_domain + 1,
+ sizeof(char *));
+ if (new_domain == NULL) {
+ os_free(val);
+ return -1;
+ }
+ new_domain[cred->num_domain++] = val;
+ cred->domain = new_domain;
+ return 0;
+ }
+
+ if (os_strcmp(var, "phase1") == 0) {
+ os_free(cred->phase1);
+ cred->phase1 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "phase2") == 0) {
+ os_free(cred->phase2);
+ cred->phase2 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "roaming_consortium length %d (3..15 "
+ "expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->roaming_consortium, val, len);
+ cred->roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
+ if (os_strcmp(var, "required_roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "required_roaming_consortium length %d "
+ "(3..15 expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->required_roaming_consortium, val, len);
+ cred->required_roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
+ if (os_strcmp(var, "excluded_ssid") == 0) {
+ struct excluded_ssid *e;
+
+ if (len > MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "excluded_ssid length %d", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+
+ e = os_realloc_array(cred->excluded_ssid,
+ cred->num_excluded_ssid + 1,
+ sizeof(struct excluded_ssid));
+ if (e == NULL) {
+ os_free(val);
+ return -1;
+ }
+ cred->excluded_ssid = e;
+
+ e = &cred->excluded_ssid[cred->num_excluded_ssid++];
+ os_memcpy(e->ssid, val, len);
+ e->ssid_len = len;
+
+ os_free(val);
+
+ return 0;
+ }
+
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
+ line, var);
+ }
+
+ os_free(val);
+
+ return -1;
+}
+
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
+{
+ struct wpa_cred *cred;
+
+ cred = config->cred;
+ while (cred) {
+ if (id == cred->id)
+ break;
+ cred = cred->next;
+ }
+
+ return cred;
+}
+
+
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
+{
+ int id;
+ struct wpa_cred *cred, *last = NULL;
+
+ id = -1;
+ cred = config->cred;
+ while (cred) {
+ if (cred->id > id)
+ id = cred->id;
+ last = cred;
+ cred = cred->next;
+ }
+ id++;
+
+ cred = os_zalloc(sizeof(*cred));
+ if (cred == NULL)
+ return NULL;
+ cred->id = id;
+ if (last)
+ last->next = cred;
+ else
+ config->cred = cred;
+
+ return cred;
+}
+
+
+int wpa_config_remove_cred(struct wpa_config *config, int id)
+{
+ struct wpa_cred *cred, *prev = NULL;
+
+ cred = config->cred;
+ while (cred) {
+ if (id == cred->id)
+ break;
+ prev = cred;
+ cred = cred->next;
+ }
+
+ if (cred == NULL)
+ return -1;
+
+ if (prev)
+ prev->next = cred->next;
+ else
+ config->cred = cred->next;
+
+ wpa_config_free_cred(cred);
+ return 0;
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
/**
* wpa_config_get_blob - Get a named configuration blob
@@ -2287,6 +2760,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
struct wpa_config *config;
+ const int aCWmin = 4, aCWmax = 10;
+ const struct hostapd_wmm_ac_params ac_bk =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wmm_ac_params ac_be =
+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -2296,11 +2778,17 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
+ config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
config->max_num_sta = DEFAULT_MAX_NUM_STA;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+ config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
+ config->wmm_ac_params[0] = ac_be;
+ config->wmm_ac_params[1] = ac_bk;
+ config->wmm_ac_params[2] = ac_vi;
+ config->wmm_ac_params[3] = ac_vo;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2349,9 +2837,18 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
{
- int *dst;
+ int val, *dst;
+ char *end;
+
dst = (int *) (((u8 *) config) + (long) data->param1);
- *dst = atoi(pos);
+ val = strtol(pos, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, pos);
+ return -1;
+ }
+ *dst = val;
+
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
if (data->param2 && *dst < (long) data->param2) {
@@ -2409,6 +2906,98 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
}
+static int wpa_config_process_bgscan(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ size_t len;
+ char *tmp;
+ int res;
+
+ tmp = wpa_config_parse_string(pos, &len);
+ if (tmp == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
+ line, data->name);
+ return -1;
+ }
+
+ res = wpa_global_config_parse_str(data, config, line, tmp);
+ os_free(tmp);
+ return res;
+}
+
+
+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)
+ 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;
+ wpa_printf(MSG_DEBUG, "%s", data->name);
+
+ return 0;
+}
+
+
+static int wpa_config_process_freq_list(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *value)
+{
+ int *freqs;
+
+ freqs = wpa_config_parse_int_array(value);
+ if (freqs == NULL)
+ return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
+ os_free(config->freq_list);
+ config->freq_list = freqs;
+ return 0;
+}
+
+
+#ifdef CONFIG_P2P
+static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ u32 *dst;
+ struct hostapd_ip_addr addr;
+
+ if (hostapd_parse_ip_addr(pos, &addr) < 0)
+ return -1;
+ if (addr.af != AF_INET)
+ return -1;
+
+ dst = (u32 *) (((u8 *) config) + (long) data->param1);
+ os_memcpy(dst, &addr.u.v4.s_addr, 4);
+ wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
+ WPA_GET_BE32((u8 *) dst));
+
+ return 0;
+}
+#endif /* CONFIG_P2P */
+
+
static int wpa_config_process_country(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
@@ -2483,6 +3072,43 @@ static int wpa_config_process_os_version(const struct global_parse_data *data,
return 0;
}
+
+static int wpa_config_process_wps_vendor_ext_m1(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+ int len = os_strlen(pos) / 2;
+ u8 *p;
+
+ if (!len) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "invalid wps_vendor_ext_m1", line);
+ return -1;
+ }
+
+ tmp = wpabuf_alloc(len);
+ if (tmp) {
+ p = wpabuf_put(tmp, len);
+
+ if (hexstr2bin(pos, p, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "invalid wps_vendor_ext_m1", line);
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ wpabuf_free(config->wps_vendor_ext_m1);
+ config->wps_vendor_ext_m1 = tmp;
+ } else {
+ wpa_printf(MSG_ERROR, "Can not allocate "
+ "memory for wps_vendor_ext_m1");
+ return -1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
@@ -2527,7 +3153,8 @@ static int wpa_config_process_p2p_pref_chan(
pos2++;
chan = atoi(pos2);
- n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel));
+ n = os_realloc_array(pref, num + 1,
+ sizeof(struct p2p_channel));
if (n == NULL)
goto fail;
pref = n;
@@ -2555,6 +3182,26 @@ fail:
wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
return -1;
}
+
+
+static int wpa_config_process_p2p_no_go_freq(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int ret;
+
+ ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
+ config->p2p_no_go_freq.num);
+
+ return 0;
+}
+
#endif /* CONFIG_P2P */
@@ -2572,6 +3219,74 @@ static int wpa_config_process_hessid(
}
+static int wpa_config_process_sae_groups(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int *groups = wpa_config_parse_int_array(pos);
+ if (groups == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
+ line, pos);
+ return -1;
+ }
+
+ os_free(config->sae_groups);
+ config->sae_groups = groups;
+
+ return 0;
+}
+
+
+static int wpa_config_process_ap_vendor_elements(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+ int len = os_strlen(pos) / 2;
+ u8 *p;
+
+ if (!len) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
+ line);
+ return -1;
+ }
+
+ tmp = wpabuf_alloc(len);
+ if (tmp) {
+ p = wpabuf_put(tmp, len);
+
+ if (hexstr2bin(pos, p, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "ap_vendor_elements", line);
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ wpabuf_free(config->ap_vendor_elements);
+ config->ap_vendor_elements = tmp;
+ } else {
+ wpa_printf(MSG_ERROR, "Cannot allocate memory for "
+ "ap_vendor_elements");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static int wpa_config_process_no_ctrl_interface(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
+ os_free(config->ctrl_interface);
+ config->ctrl_interface = NULL;
+ return 0;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
#ifdef OFFSET
#undef OFFSET
#endif /* OFFSET */
@@ -2586,18 +3301,26 @@ static int wpa_config_process_hessid(
#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
#define STR(f) _STR(f), NULL, NULL
#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
+#define IPV4(f) #f, wpa_global_config_parse_ipv4, OFFSET(f), NULL, NULL
static const struct global_parse_data global_fields[] = {
#ifdef CONFIG_CTRL_IFACE
{ STR(ctrl_interface), 0 },
+ { FUNC_NO_VAR(no_ctrl_interface), 0 },
{ STR(ctrl_interface_group), 0 } /* deprecated */,
#endif /* CONFIG_CTRL_IFACE */
{ INT_RANGE(eapol_version, 1, 2), 0 },
{ INT(ap_scan), 0 },
+ { FUNC(bgscan), 0 },
+ { INT(disable_scan_offload), 0 },
{ INT(fast_reauth), 0 },
{ STR(opensc_engine_path), 0 },
{ STR(pkcs11_engine_path), 0 },
{ STR(pkcs11_module_path), 0 },
+ { STR(pcsc_reader), 0 },
+ { STR(pcsc_pin), 0 },
+ { INT(external_sim), 0 },
{ STR(driver_param), 0 },
{ INT(dot11RSNAConfigPMKLifetime), 0 },
{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -2617,36 +3340,67 @@ static const struct global_parse_data global_fields[] = {
{ FUNC(os_version), CFG_CHANGED_OS_VERSION },
{ STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
{ INT_RANGE(wps_cred_processing, 0, 2), 0 },
+ { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
{ INT(p2p_listen_reg_class), 0 },
{ INT(p2p_listen_channel), 0 },
- { INT(p2p_oper_reg_class), 0 },
- { INT(p2p_oper_channel), 0 },
+ { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
+ { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
{ INT(p2p_group_idle), 0 },
{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+ { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
+ { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
+ { INT(p2p_go_ht40), 0 },
+ { INT(p2p_go_vht), 0 },
+ { INT(p2p_disabled), 0 },
+ { INT(p2p_no_group_iface), 0 },
+ { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
+ { IPV4(ip_addr_go), 0 },
+ { IPV4(ip_addr_mask), 0 },
+ { IPV4(ip_addr_start), 0 },
+ { IPV4(ip_addr_end), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
{ INT(bss_expiration_age), 0 },
{ INT(bss_expiration_scan_count), 0 },
{ INT_RANGE(filter_ssids, 0, 1), 0 },
+ { INT_RANGE(filter_rssi, -100, 0), 0 },
{ INT(max_num_sta), 0 },
{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
- { STR(home_realm), 0 },
- { STR(home_username), 0 },
- { STR(home_password), 0 },
- { STR(home_ca_cert), 0 },
- { STR(home_imsi), 0 },
- { STR(home_milenage), 0 },
+#ifdef CONFIG_HS20
+ { INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
{ INT_RANGE(interworking, 0, 1), 0 },
{ FUNC(hessid), 0 },
- { INT_RANGE(access_network_type, 0, 15), 0 }
+ { INT_RANGE(access_network_type, 0, 15), 0 },
+ { INT_RANGE(pbc_in_m1, 0, 1), 0 },
+ { STR(autoscan), 0 },
+ { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
+ CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+ { INT(p2p_go_max_inactivity), 0 },
+ { INT_RANGE(auto_interworking, 0, 1), 0 },
+ { INT(okc), 0 },
+ { INT(pmf), 0 },
+ { FUNC(sae_groups), 0 },
+ { INT(dtim_period), 0 },
+ { INT(beacon_int), 0 },
+ { FUNC(ap_vendor_elements), 0 },
+ { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
+ { FUNC(freq_list), 0 },
+ { INT(scan_cur_freq), 0 },
+ { INT(sched_scan_interval), 0 },
+ { INT(tdls_external_control), 0},
};
#undef FUNC
@@ -2656,7 +3410,9 @@ static const struct global_parse_data global_fields[] = {
#undef _STR
#undef STR
#undef STR_RANGE
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+#undef BIN
+#undef IPV4
+#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
@@ -2676,10 +3432,31 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
"parse '%s'.", line, pos);
ret = -1;
}
+ if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
+ config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
break;
}
if (i == NUM_GLOBAL_FIELDS) {
+#ifdef CONFIG_AP
+ if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
+ char *tmp = os_strchr(pos, '=');
+ if (tmp == NULL) {
+ if (line < 0)
+ return -1;
+ wpa_printf(MSG_ERROR, "Line %d: invalid line "
+ "'%s'", line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+ "AC item", line);
+ return -1;
+ }
+ }
+#endif /* CONFIG_AP */
if (line < 0)
return -1;
wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 18317f5..e7bdaa5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1,15 +1,9 @@
/*
* WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CONFIG_H
@@ -24,14 +18,225 @@
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
+#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
#define DEFAULT_BSS_MAX_COUNT 200
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
#define DEFAULT_MAX_NUM_STA 128
#define DEFAULT_ACCESS_NETWORK_TYPE 15
+#define DEFAULT_SCAN_CUR_FREQ 0
#include "config_ssid.h"
#include "wps/wps.h"
+#include "common/ieee802_11_common.h"
+
+
+struct wpa_cred {
+ /**
+ * next - Next credential in the list
+ *
+ * This pointer can be used to iterate over all credentials. The head
+ * of this list is stored in the cred field of struct wpa_config.
+ */
+ struct wpa_cred *next;
+
+ /**
+ * id - Unique id for the credential
+ *
+ * This identifier is used as a unique identifier for each credential
+ * block when using the control interface. Each credential is allocated
+ * an id when it is being created, either when reading the
+ * configuration file or when a new credential is added through the
+ * control interface.
+ */
+ int id;
+
+ /**
+ * temporary - Whether this credential is temporary and not to be saved
+ */
+ int temporary;
+
+ /**
+ * priority - Priority group
+ *
+ * By default, all networks and credentials get the same priority group
+ * (0). This field can be used to give higher priority for credentials
+ * (and similarly in struct wpa_ssid for network blocks) to change the
+ * Interworking automatic networking selection behavior. The matching
+ * network (based on either an enabled network block or a credential)
+ * with the highest priority value will be selected.
+ */
+ int priority;
+
+ /**
+ * pcsc - Use PC/SC and SIM/USIM card
+ */
+ int pcsc;
+
+ /**
+ * realm - Home Realm for Interworking
+ */
+ char *realm;
+
+ /**
+ * username - Username for Interworking network selection
+ */
+ char *username;
+
+ /**
+ * password - Password for Interworking network selection
+ */
+ char *password;
+
+ /**
+ * ext_password - Whether password is a name for external storage
+ */
+ int ext_password;
+
+ /**
+ * ca_cert - CA certificate for Interworking network selection
+ */
+ char *ca_cert;
+
+ /**
+ * client_cert - File path to client certificate file (PEM/DER)
+ *
+ * This field is used with Interworking networking selection for a case
+ * where client certificate/private key is used for authentication
+ * (EAP-TLS). Full path to the file should be used since working
+ * directory may change when wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://blob_name.
+ */
+ char *client_cert;
+
+ /**
+ * private_key - File path to client private key file (PEM/DER/PFX)
+ *
+ * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+ * commented out. Both the private key and certificate will be read
+ * from the PKCS#12 file in this case. Full path to the file should be
+ * used since working directory may change when wpa_supplicant is run
+ * in the background.
+ *
+ * Windows certificate store can be used by leaving client_cert out and
+ * configuring private_key in one of the following formats:
+ *
+ * cert://substring_to_match
+ *
+ * hash://certificate_thumbprint_in_hex
+ *
+ * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+ *
+ * Note that when running wpa_supplicant as an application, the user
+ * certificate store (My user account) is used, whereas computer store
+ * (Computer account) is used when running wpasvc as a service.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://blob_name.
+ */
+ char *private_key;
+
+ /**
+ * private_key_passwd - Password for private key file
+ */
+ char *private_key_passwd;
+
+ /**
+ * imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+ */
+ char *imsi;
+
+ /**
+ * milenage - Milenage parameters for SIM/USIM simulator in
+ * <Ki>:<OPc>:<SQN> format
+ */
+ char *milenage;
+
+ /**
+ * domain_suffix_match - Constraint for server domain name
+ *
+ * If set, this FQDN is 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 SubjetName CN
+ * using same suffix match comparison. Suffix match here means that the
+ * host/domain name is compared one label at a time starting from the
+ * top-level domain and all the labels in @domain_suffix_match shall be
+ * included in the certificate. The certificate may include additional
+ * sub-level labels in addition to the required labels.
+ *
+ * For example, domain_suffix_match=example.com would match
+ * test.example.com but would not match test-example.com.
+ */
+ char *domain_suffix_match;
+
+ /**
+ * domain - Home service provider FQDN(s)
+ *
+ * This is used to compare against the Domain Name List to figure out
+ * whether the AP is operated by the Home SP. Multiple domain entries
+ * can be used to configure alternative FQDNs that will be considered
+ * home networks.
+ */
+ char **domain;
+
+ /**
+ * num_domain - Number of FQDNs in the domain array
+ */
+ size_t num_domain;
+
+ /**
+ * roaming_consortium - Roaming Consortium OI
+ *
+ * If roaming_consortium_len is non-zero, this field contains the
+ * Roaming Consortium OI that can be used to determine which access
+ * points support authentication with this credential. This is an
+ * alternative to the use of the realm parameter. When using Roaming
+ * Consortium to match the network, the EAP parameters need to be
+ * pre-configured with the credential since the NAI Realm information
+ * may not be available or fetched.
+ */
+ u8 roaming_consortium[15];
+
+ /**
+ * roaming_consortium_len - Length of roaming_consortium
+ */
+ size_t roaming_consortium_len;
+
+ u8 required_roaming_consortium[15];
+ size_t required_roaming_consortium_len;
+
+ /**
+ * eap_method - EAP method to use
+ *
+ * Pre-configured EAP method to use with this credential or %NULL to
+ * indicate no EAP method is selected, i.e., the method will be
+ * selected automatically based on ANQP information.
+ */
+ struct eap_method_type *eap_method;
+
+ /**
+ * phase1 - Phase 1 (outer authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase1;
+
+ /**
+ * phase2 - Phase 2 (inner authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase2;
+
+ struct excluded_ssid {
+ u8 ssid[MAX_SSID_LEN];
+ size_t ssid_len;
+ } *excluded_ssid;
+ size_t num_excluded_ssid;
+};
#define CFG_CHANGED_DEVICE_NAME BIT(0)
@@ -48,6 +253,8 @@
#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
+#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -79,6 +286,13 @@ struct wpa_config {
int num_prio;
/**
+ * cred - Head of the credential list
+ *
+ * This is the head for the list of all the configured credentials.
+ */
+ struct wpa_cred *cred;
+
+ /**
* eapol_version - IEEE 802.1X/EAPOL version number
*
* wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which
@@ -120,6 +334,27 @@ struct wpa_config {
int ap_scan;
/**
+ * bgscan - Background scan and roaming parameters or %NULL if none
+ *
+ * This is an optional set of parameters for background scanning and
+ * roaming within a network (ESS). For more detailed information see
+ * ssid block documentation.
+ *
+ * The variable defines default bgscan behavior for all BSS station
+ * networks except for those which have their own bgscan configuration.
+ */
+ char *bgscan;
+
+ /**
+ * disable_scan_offload - Disable automatic offloading of scan requests
+ *
+ * By default, %wpa_supplicant tries to offload scanning if the driver
+ * indicates support for this (sched_scan). This configuration
+ * parameter can be used to disable this offloading mechanism.
+ */
+ int disable_scan_offload;
+
+ /**
* ctrl_interface - Parameters for the control interface
*
* If this is specified, %wpa_supplicant will open a control interface
@@ -218,6 +453,28 @@ struct wpa_config {
char *pkcs11_module_path;
/**
+ * pcsc_reader - PC/SC reader name prefix
+ *
+ * If not %NULL, PC/SC reader with a name that matches this prefix is
+ * initialized for SIM/USIM access. Empty string can be used to match
+ * the first available reader.
+ */
+ char *pcsc_reader;
+
+ /**
+ * pcsc_pin - PIN for USIM, GSM SIM, and smartcards
+ *
+ * This field is used to configure PIN for SIM/USIM for EAP-SIM and
+ * EAP-AKA. If left out, this will be asked through control interface.
+ */
+ char *pcsc_pin;
+
+ /**
+ * external_sim - Use external processing for SIM/USIM operations
+ */
+ int external_sim;
+
+ /**
* driver_param - Driver interface parameters
*
* This text string is passed to the selected driver interface with the
@@ -365,6 +622,11 @@ struct wpa_config {
int p2p_intra_bss;
unsigned int num_p2p_pref_chan;
struct p2p_channel *p2p_pref_chan;
+ struct wpa_freq_range_list p2p_no_go_freq;
+ int p2p_add_cli_chan;
+ int p2p_ignore_shared_freq;
+
+ struct wpabuf *wps_vendor_ext_m1;
#define MAX_WPS_VENDOR_EXT 10
/**
@@ -383,9 +645,12 @@ struct wpa_config {
* state indefinitely until explicitly removed. As a P2P client, the
* maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
* this parameter is mainly meant for GO use and for P2P client, it can
- * only be used to reduce the default timeout to smaller value.
+ * only be used to reduce the default timeout to smaller value. A
+ * special value -1 can be used to configure immediate removal of the
+ * group for P2P client role on any disconnection after the data
+ * connection has been established.
*/
- unsigned int p2p_group_idle;
+ int p2p_group_idle;
/**
* bss_max_count - Maximum number of BSS entries to keep in memory
@@ -420,11 +685,35 @@ struct wpa_config {
int filter_ssids;
/**
+ * filter_rssi - RSSI-based scan result filtering
+ *
+ * 0 = do not filter scan results
+ * -n = filter scan results below -n dBm
+ */
+ int filter_rssi;
+
+ /**
* max_num_sta - Maximum number of STAs in an AP/P2P GO
*/
unsigned int max_num_sta;
/**
+ * freq_list - Array of allowed scan frequencies or %NULL for all
+ *
+ * This is an optional zero-terminated array of frequencies in
+ * megahertz (MHz) to allow for narrowing scanning range.
+ */
+ int *freq_list;
+
+ /**
+ * scan_cur_freq - Whether to scan only the current channel
+ *
+ * If true, attempt to scan only the current channel if any other
+ * VIFs on this radio are already associated on a particular channel.
+ */
+ int scan_cur_freq;
+
+ /**
* changed_parameters - Bitmap of changed parameters since last update
*/
unsigned int changed_parameters;
@@ -458,35 +747,212 @@ struct wpa_config {
u8 hessid[ETH_ALEN];
/**
- * home_realm - Home Realm for Interworking
+ * hs20 - Hotspot 2.0
*/
- char *home_realm;
+ int hs20;
/**
- * home_username - Username for Interworking network selection
+ * pbc_in_m1 - AP mode WPS probing workaround for PBC with Windows 7
+ *
+ * Windows 7 uses incorrect way of figuring out AP's WPS capabilities
+ * by acting as a Registrar and using M1 from the AP. The config
+ * methods attribute in that message is supposed to indicate only the
+ * configuration method supported by the AP in Enrollee role, i.e., to
+ * add an external Registrar. For that case, PBC shall not be used and
+ * as such, the PushButton config method is removed from M1 by default.
+ * If pbc_in_m1=1 is included in the configuration file, the PushButton
+ * config method is left in M1 (if included in config_methods
+ * parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from
+ * a label in the AP).
*/
- char *home_username;
+ int pbc_in_m1;
/**
- * home_password - Password for Interworking network selection
+ * autoscan - Automatic scan parameters or %NULL if none
+ *
+ * This is an optional set of parameters for automatic scanning
+ * within an interface in following format:
+ * <autoscan module name>:<module parameters>
*/
- char *home_password;
+ char *autoscan;
/**
- * home_ca_cert - CA certificate for Interworking network selection
+ * wps_nfc_pw_from_config - NFC Device Password was read from config
+ *
+ * This parameter can be determined whether the NFC Device Password was
+ * included in the configuration (1) or generated dynamically (0). Only
+ * the former case is re-written back to the configuration file.
*/
- char *home_ca_cert;
+ int wps_nfc_pw_from_config;
/**
- * home_imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+ * wps_nfc_dev_pw_id - NFC Device Password ID for password token
*/
- char *home_imsi;
+ int wps_nfc_dev_pw_id;
/**
- * home_milenage - Milenage parameters for SIM/USIM simulator in
- * <Ki>:<OPc>:<SQN> format
+ * wps_nfc_dh_pubkey - NFC DH Public Key for password token
+ */
+ struct wpabuf *wps_nfc_dh_pubkey;
+
+ /**
+ * wps_nfc_dh_privkey - NFC DH Private Key for password token
+ */
+ struct wpabuf *wps_nfc_dh_privkey;
+
+ /**
+ * wps_nfc_dev_pw - NFC Device Password for password token
*/
- char *home_milenage;
+ struct wpabuf *wps_nfc_dev_pw;
+
+ /**
+ * ext_password_backend - External password backend or %NULL if none
+ *
+ * format: <backend name>[:<optional backend parameters>]
+ */
+ char *ext_password_backend;
+
+ /*
+ * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in P2P GO mode to clean up
+ * inactive stations.
+ * By default: 300 seconds.
+ */
+ int p2p_go_max_inactivity;
+
+ struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+ /**
+ * auto_interworking - Whether to use network selection automatically
+ *
+ * 0 = do not automatically go through Interworking network selection
+ * (i.e., require explicit interworking_select command for this)
+ * 1 = perform Interworking network selection if one or more
+ * credentials have been configured and scan did not find a
+ * matching network block
+ */
+ int auto_interworking;
+
+ /**
+ * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_ht40;
+
+ /**
+ * p2p_go_vht - Default mode for VHT enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_vht;
+
+ /**
+ * p2p_disabled - Whether P2P operations are disabled for this interface
+ */
+ int p2p_disabled;
+
+ /**
+ * p2p_no_group_iface - Whether group interfaces can be used
+ *
+ * By default, wpa_supplicant will create a separate interface for P2P
+ * group operations if the driver supports this. This functionality can
+ * be disabled by setting this parameter to 1. In that case, the same
+ * interface that was used for the P2P management operations is used
+ * also for the group operation.
+ */
+ int p2p_no_group_iface;
+
+ /**
+ * okc - Whether to enable opportunistic key caching by default
+ *
+ * By default, OKC is disabled unless enabled by the per-network
+ * proactive_key_caching=1 parameter. okc=1 can be used to change this
+ * default behavior.
+ */
+ int okc;
+
+ /**
+ * pmf - Whether to enable/require PMF by default
+ *
+ * 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.
+ */
+ enum mfp_options pmf;
+
+ /**
+ * sae_groups - Preference list of enabled groups for SAE
+ *
+ * By default (if this parameter is not set), the mandatory group 19
+ * (ECC group defined over a 256-bit prime order field) is preferred,
+ * but other groups are also enabled. If this parameter is set, the
+ * groups will be tried in the indicated order.
+ */
+ int *sae_groups;
+
+ /**
+ * dtim_period - Default DTIM period in Beacon intervals
+ *
+ * This parameter can be used to set the default value for network
+ * blocks that do not specify dtim_period.
+ */
+ int dtim_period;
+
+ /**
+ * beacon_int - Default Beacon interval in TU
+ *
+ * This parameter can be used to set the default value for network
+ * blocks that do not specify beacon_int.
+ */
+ int beacon_int;
+
+ /**
+ * ap_vendor_elements: Vendor specific elements for Beacon/ProbeResp
+ *
+ * This parameter can be used to define additional vendor specific
+ * elements for Beacon and Probe Response frames in AP/P2P GO mode. The
+ * format for these element(s) is a hexdump of the raw information
+ * elements (id+len+payload for one or more elements).
+ */
+ struct wpabuf *ap_vendor_elements;
+
+ /**
+ * ignore_old_scan_res - Ignore scan results older than request
+ *
+ * The driver may have a cache of scan results that makes it return
+ * information that is older than our scan trigger. This parameter can
+ * be used to configure such old information to be ignored instead of
+ * allowing it to update the internal BSS table.
+ */
+ int ignore_old_scan_res;
+
+ /**
+ * sched_scan_interval - schedule scan interval
+ */
+ unsigned int sched_scan_interval;
+
+ /**
+ * tdls_external_control - External control for TDLS setup requests
+ *
+ * Enable TDLS mode where external programs are given the control
+ * to specify the TDLS link to get established to the driver. The
+ * driver requests the TDLS setup to the supplicant only for the
+ * specified TDLS peers.
+ */
+ int tdls_external_control;
+
+ u8 ip_addr_go[4];
+ u8 ip_addr_mask[4];
+ u8 ip_addr_start[4];
+ u8 ip_addr_end[4];
};
@@ -518,6 +984,14 @@ void wpa_config_set_blob(struct wpa_config *config,
struct wpa_config_blob *blob);
void wpa_config_free_blob(struct wpa_config_blob *blob);
int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+void wpa_config_flush_blobs(struct wpa_config *config);
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
+int wpa_config_remove_cred(struct wpa_config *config, int id);
+void wpa_config_free_cred(struct wpa_cred *cred);
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+ const char *value, int line);
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param);
@@ -538,6 +1012,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
* wpa_config_read - Read and parse configuration database
* @name: Name of the configuration (e.g., path and file name for the
* configuration file)
+ * @cfgp: Pointer to previously allocated configuration data or %NULL if none
* Returns: Pointer to allocated configuration data or %NULL on failure
*
* This function reads configuration data, parses its contents, and allocates
@@ -546,7 +1021,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
*
* Each configuration backend needs to implement this function.
*/
-struct wpa_config * wpa_config_read(const char *name);
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp);
/**
* wpa_config_write - Write or update configuration data
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index c0e4ad0..6312a77 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This file implements a configuration backend for text files. All the
* configuration information is stored in a text file that uses a format
@@ -23,6 +17,8 @@
#include "base64.h"
#include "uuid.h"
#include "p2p/p2p.h"
+#include "eap_peer/eap_methods.h"
+#include "eap_peer/eap.h"
static int newline_terminated(const char *buf, size_t buflen)
@@ -137,14 +133,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
wpa_config_update_psk(ssid);
}
- if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_PSK_SHA256)) &&
- !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
- "management, but no PSK configured.", line);
- errors++;
- }
-
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
@@ -170,6 +158,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
ssid = os_zalloc(sizeof(*ssid));
if (ssid == NULL)
return NULL;
+ dl_list_init(&ssid->psk_list);
ssid->id = id;
wpa_config_set_network_defaults(ssid);
@@ -219,6 +208,61 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
}
+static struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id)
+{
+ struct wpa_cred *cred;
+ int errors = 0, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new cred block", *line);
+ cred = os_zalloc(sizeof(*cred));
+ if (cred == NULL)
+ return NULL;
+ cred->id = id;
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+ if (os_strcmp(pos, "}") == 0) {
+ end = 1;
+ break;
+ }
+
+ pos2 = os_strchr(pos, '=');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid cred line "
+ "'%s'.", *line, pos);
+ errors++;
+ continue;
+ }
+
+ *pos2++ = '\0';
+ if (*pos2 == '"') {
+ if (os_strchr(pos2 + 1, '"') == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "quotation '%s'.", *line, pos2);
+ errors++;
+ continue;
+ }
+ }
+
+ if (wpa_config_set_cred(cred, pos, pos2, *line) < 0)
+ errors++;
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR, "Line %d: cred block was not "
+ "terminated properly.", *line);
+ errors++;
+ }
+
+ if (errors) {
+ wpa_config_free_cred(cred);
+ cred = NULL;
+ }
+
+ return cred;
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
const char *name)
@@ -302,21 +346,36 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
#endif /* CONFIG_NO_CONFIG_BLOBS */
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
FILE *f;
- char buf[256], *pos;
+ char buf[512], *pos;
int errors = 0, line = 0;
struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
struct wpa_config *config;
int id = 0;
+ int cred_id = 0;
- config = wpa_config_alloc_empty(NULL, NULL);
- if (config == NULL)
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
+ if (config == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate config file "
+ "structure");
return NULL;
+ }
+ head = config->ssid;
+ cred_head = config->cred;
+
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
os_free(config);
return NULL;
}
@@ -343,10 +402,26 @@ struct wpa_config * wpa_config_read(const char *name)
errors++;
continue;
}
+ } else if (os_strcmp(pos, "cred={") == 0) {
+ cred = wpa_config_read_cred(f, &line, cred_id++);
+ if (cred == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse cred block.", line);
+ errors++;
+ continue;
+ }
+ if (cred_head == NULL) {
+ cred_head = cred_tail = cred;
+ } else {
+ cred_tail->next = cred;
+ cred_tail = cred;
+ }
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
if (wpa_config_process_blob(config, f, &line, pos + 12)
< 0) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "process blob.", line);
errors++;
continue;
}
@@ -363,6 +438,7 @@ struct wpa_config * wpa_config_read(const char *name)
config->ssid = head;
wpa_config_debug_dump_networks(config);
+ config->cred = cred_head;
#ifndef WPA_IGNORE_CONFIG_ERRORS
if (errors) {
@@ -529,6 +605,16 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
#ifdef CONFIG_P2P
+
+static void write_go_p2p_dev_addr(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "go_p2p_dev_addr");
+ if (value == NULL)
+ return;
+ fprintf(f, "\tgo_p2p_dev_addr=%s\n", value);
+ os_free(value);
+}
+
static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
{
char *value = wpa_config_get(ssid, "p2p_client_list");
@@ -537,6 +623,20 @@ static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
fprintf(f, "\tp2p_client_list=%s\n", value);
os_free(value);
}
+
+
+static void write_psk_list(FILE *f, struct wpa_ssid *ssid)
+{
+ struct psk_list_entry *psk;
+ char hex[32 * 2 + 1];
+
+ dl_list_for_each(psk, &ssid->psk_list, struct psk_list_entry, list) {
+ wpa_snprintf_hex(hex, sizeof(hex), psk->psk, sizeof(psk->psk));
+ fprintf(f, "\tpsk_list=%s" MACSTR "-%s\n",
+ psk->p2p ? "P2P-" : "", MAC2STR(psk->addr), hex);
+ }
+}
+
#endif /* CONFIG_P2P */
@@ -556,10 +656,13 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_psk(f, ssid);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
+ INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
write_pairwise(f, ssid);
write_group(f, ssid);
write_auth_alg(f, ssid);
STR(bgscan);
+ STR(autoscan);
+ STR(scan_freq);
#ifdef IEEE8021X_EAPOL
write_eap(f, ssid);
STR(identity);
@@ -573,6 +676,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dh_file);
STR(subject_match);
STR(altsubject_match);
+ STR(domain_suffix_match);
STR(ca_cert2);
STR(ca_path2);
STR(client_cert2);
@@ -581,6 +685,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dh_file2);
STR(subject_match2);
STR(altsubject_match2);
+ STR(domain_suffix_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
@@ -608,16 +713,22 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
- INT(proactive_key_caching);
+ INT(frequency);
+ write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
#ifdef CONFIG_IEEE80211W
- INT(ieee80211w);
+ write_int(f, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
+ write_go_p2p_dev_addr(f, ssid);
write_p2p_client_list(f, ssid);
+ write_psk_list(f, ssid);
#endif /* CONFIG_P2P */
+ INT(dtim_period);
+ INT(beacon_int);
#undef STR
#undef INT
@@ -625,6 +736,69 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
}
+static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
+{
+ size_t i;
+
+ if (cred->priority)
+ fprintf(f, "\tpriority=%d\n", cred->priority);
+ if (cred->pcsc)
+ fprintf(f, "\tpcsc=%d\n", cred->pcsc);
+ if (cred->realm)
+ fprintf(f, "\trealm=\"%s\"\n", cred->realm);
+ if (cred->username)
+ fprintf(f, "\tusername=\"%s\"\n", cred->username);
+ if (cred->password && cred->ext_password)
+ fprintf(f, "\tpassword=ext:%s\n", cred->password);
+ else if (cred->password)
+ fprintf(f, "\tpassword=\"%s\"\n", cred->password);
+ if (cred->ca_cert)
+ fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert);
+ if (cred->client_cert)
+ fprintf(f, "\tclient_cert=\"%s\"\n", cred->client_cert);
+ if (cred->private_key)
+ fprintf(f, "\tprivate_key=\"%s\"\n", cred->private_key);
+ if (cred->private_key_passwd)
+ fprintf(f, "\tprivate_key_passwd=\"%s\"\n",
+ cred->private_key_passwd);
+ if (cred->imsi)
+ fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
+ if (cred->milenage)
+ fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
+ for (i = 0; i < cred->num_domain; i++)
+ fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]);
+ if (cred->domain_suffix_match)
+ fprintf(f, "\tdomain_suffix_match=\"%s\"",
+ cred->domain_suffix_match);
+ if (cred->roaming_consortium_len) {
+ fprintf(f, "\troaming_consortium=");
+ for (i = 0; i < cred->roaming_consortium_len; i++)
+ fprintf(f, "%02x", cred->roaming_consortium[i]);
+ fprintf(f, "\n");
+ }
+ if (cred->eap_method) {
+ const char *name;
+ name = eap_get_name(cred->eap_method[0].vendor,
+ cred->eap_method[0].method);
+ fprintf(f, "\teap=%s\n", name);
+ }
+ if (cred->phase1)
+ fprintf(f, "\tphase1=\"%s\"\n", cred->phase1);
+ if (cred->phase2)
+ fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
+ if (cred->excluded_ssid) {
+ size_t j;
+ for (i = 0; i < cred->num_excluded_ssid; i++) {
+ struct excluded_ssid *e = &cred->excluded_ssid[i];
+ fprintf(f, "\texcluded_ssid=");
+ for (j = 0; j < e->ssid_len; j++)
+ fprintf(f, "%02x", e->ssid[j]);
+ fprintf(f, "\n");
+ }
+ }
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
@@ -641,6 +815,23 @@ static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
#endif /* CONFIG_NO_CONFIG_BLOBS */
+static void write_global_bin(FILE *f, const char *field,
+ const struct wpabuf *val)
+{
+ size_t i;
+ const u8 *pos;
+
+ if (val == NULL)
+ return;
+
+ fprintf(f, "%s=", field);
+ pos = wpabuf_head(val);
+ for (i = 0; i < wpabuf_len(val); i++)
+ fprintf(f, "%02X", *pos++);
+ fprintf(f, "\n");
+}
+
+
static void wpa_config_write_global(FILE *f, struct wpa_config *config)
{
#ifdef CONFIG_CTRL_IFACE
@@ -654,6 +845,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "eapol_version=%d\n", config->eapol_version);
if (config->ap_scan != DEFAULT_AP_SCAN)
fprintf(f, "ap_scan=%d\n", config->ap_scan);
+ if (config->disable_scan_offload)
+ fprintf(f, "disable_scan_offload=%d\n",
+ config->disable_scan_offload);
if (config->fast_reauth != DEFAULT_FAST_REAUTH)
fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
if (config->opensc_engine_path)
@@ -665,6 +859,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->pkcs11_module_path)
fprintf(f, "pkcs11_module_path=%s\n",
config->pkcs11_module_path);
+ if (config->pcsc_reader)
+ fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
+ if (config->pcsc_pin)
+ fprintf(f, "pcsc_pin=%s\n", config->pcsc_pin);
if (config->driver_param)
fprintf(f, "driver_param=%s\n", config->driver_param);
if (config->dot11RSNAConfigPMKLifetime)
@@ -709,6 +907,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->wps_cred_processing)
fprintf(f, "wps_cred_processing=%d\n",
config->wps_cred_processing);
+ if (config->wps_vendor_ext_m1) {
+ int i, len = wpabuf_len(config->wps_vendor_ext_m1);
+ const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1);
+ if (len > 0) {
+ fprintf(f, "wps_vendor_ext_m1=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
if (config->p2p_listen_reg_class)
@@ -743,6 +951,27 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
fprintf(f, "\n");
}
+ if (config->p2p_no_go_freq.num) {
+ char *val = freq_range_list_str(&config->p2p_no_go_freq);
+ if (val) {
+ fprintf(f, "p2p_no_go_freq=%s\n", val);
+ os_free(val);
+ }
+ }
+ if (config->p2p_add_cli_chan)
+ fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
+ if (config->p2p_go_ht40)
+ fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+ if (config->p2p_go_vht)
+ fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht);
+ if (config->p2p_disabled)
+ fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
+ if (config->p2p_no_group_iface)
+ fprintf(f, "p2p_no_group_iface=%u\n",
+ config->p2p_no_group_iface);
+ if (config->p2p_ignore_shared_freq)
+ fprintf(f, "p2p_ignore_shared_freq=%u\n",
+ config->p2p_ignore_shared_freq);
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
@@ -763,19 +992,11 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
if (config->disassoc_low_ack)
fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
+#ifdef CONFIG_HS20
+ if (config->hs20)
+ fprintf(f, "hs20=1\n");
+#endif /* CONFIG_HS20 */
#ifdef CONFIG_INTERWORKING
- if (config->home_realm)
- fprintf(f, "home_realm=%s\n", config->home_realm);
- if (config->home_username)
- fprintf(f, "home_username=%s\n", config->home_username);
- if (config->home_password)
- fprintf(f, "home_password=%s\n", config->home_password);
- if (config->home_ca_cert)
- fprintf(f, "home_ca_cert=%s\n", config->home_ca_cert);
- if (config->home_imsi)
- fprintf(f, "home_imsi=%s\n", config->home_imsi);
- if (config->home_milenage)
- fprintf(f, "home_milenage=%s\n", config->home_milenage);
if (config->interworking)
fprintf(f, "interworking=%u\n", config->interworking);
if (!is_zero_ether_addr(config->hessid))
@@ -784,6 +1005,84 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "access_network_type=%d\n",
config->access_network_type);
#endif /* CONFIG_INTERWORKING */
+ if (config->pbc_in_m1)
+ fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
+ if (config->wps_nfc_pw_from_config) {
+ if (config->wps_nfc_dev_pw_id)
+ fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+ config->wps_nfc_dev_pw_id);
+ write_global_bin(f, "wps_nfc_dh_pubkey",
+ config->wps_nfc_dh_pubkey);
+ write_global_bin(f, "wps_nfc_dh_privkey",
+ config->wps_nfc_dh_privkey);
+ write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+ }
+
+ if (config->ext_password_backend)
+ fprintf(f, "ext_password_backend=%s\n",
+ config->ext_password_backend);
+ if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY)
+ fprintf(f, "p2p_go_max_inactivity=%d\n",
+ config->p2p_go_max_inactivity);
+ if (config->auto_interworking)
+ fprintf(f, "auto_interworking=%d\n",
+ config->auto_interworking);
+ if (config->okc)
+ fprintf(f, "okc=%d\n", config->okc);
+ if (config->pmf)
+ fprintf(f, "pmf=%d\n", config->pmf);
+ if (config->dtim_period)
+ fprintf(f, "dtim_period=%d\n", config->dtim_period);
+ if (config->beacon_int)
+ fprintf(f, "beacon_int=%d\n", config->beacon_int);
+
+ if (config->sae_groups) {
+ int i;
+ fprintf(f, "sae_groups=");
+ for (i = 0; config->sae_groups[i] >= 0; i++) {
+ fprintf(f, "%s%d", i > 0 ? " " : "",
+ config->sae_groups[i]);
+ }
+ fprintf(f, "\n");
+ }
+
+ if (config->ap_vendor_elements) {
+ int i, len = wpabuf_len(config->ap_vendor_elements);
+ const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
+ if (len > 0) {
+ fprintf(f, "ap_vendor_elements=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
+
+ if (config->ignore_old_scan_res)
+ fprintf(f, "ignore_old_scan_res=%d\n",
+ config->ignore_old_scan_res);
+
+ if (config->freq_list && config->freq_list[0]) {
+ int i;
+ fprintf(f, "freq_list=");
+ for (i = 0; config->freq_list[i]; i++) {
+ fprintf(f, "%s%u", i > 0 ? " " : "",
+ config->freq_list[i]);
+ }
+ fprintf(f, "\n");
+ }
+ if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
+ fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+
+ if (config->sched_scan_interval)
+ fprintf(f, "sched_scan_interval=%u\n",
+ config->sched_scan_interval);
+
+ if (config->external_sim)
+ fprintf(f, "external_sim=%d\n", config->external_sim);
+
+ if (config->tdls_external_control)
+ fprintf(f, "tdls_external_control=%d\n",
+ config->tdls_external_control);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -794,6 +1093,7 @@ int wpa_config_write(const char *name, struct wpa_config *config)
#ifndef CONFIG_NO_CONFIG_WRITE
FILE *f;
struct wpa_ssid *ssid;
+ struct wpa_cred *cred;
#ifndef CONFIG_NO_CONFIG_BLOBS
struct wpa_config_blob *blob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
@@ -809,6 +1109,14 @@ int wpa_config_write(const char *name, struct wpa_config *config)
wpa_config_write_global(f, config);
+ for (cred = config->cred; cred; cred = cred->next) {
+ if (cred->temporary)
+ continue;
+ fprintf(f, "\ncred={\n");
+ wpa_config_write_cred(f, cred);
+ fprintf(f, "}\n");
+ }
+
for (ssid = config->ssid; ssid; ssid = ssid->next) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
continue; /* do not save temporary networks */
diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c
index 2e9ccc0..2aac28f 100644
--- a/wpa_supplicant/config_none.c
+++ b/wpa_supplicant/config_none.c
@@ -2,14 +2,8 @@
* WPA Supplicant / Configuration backend: empty starting point
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This file implements dummy example of a configuration backend. None of the
* functions are actually implemented so this can be used as a simple
@@ -23,11 +17,16 @@
#include "base64.h"
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
struct wpa_config *config;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
return NULL;
/* TODO: fill in configuration data */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index eb496b9..d515030 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -1,21 +1,16 @@
/*
* WPA Supplicant / Network configuration structures
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CONFIG_SSID_H
#define CONFIG_SSID_H
#include "common/defs.h"
+#include "utils/list.h"
#include "eap_peer/eap_config.h"
#define MAX_SSID_LEN 32
@@ -31,6 +26,21 @@
WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
#define DEFAULT_FRAGMENT_SIZE 1398
+#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_DISABLE_HT 0
+#define DEFAULT_DISABLE_HT40 0
+#define DEFAULT_DISABLE_SGI 0
+#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
+#define DEFAULT_AMPDU_FACTOR -1 /* no change */
+#define DEFAULT_AMPDU_DENSITY -1 /* no change */
+
+struct psk_list_entry {
+ struct dl_list list;
+ u8 addr[ETH_ALEN];
+ u8 psk[32];
+ u8 p2p;
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -121,6 +131,11 @@ struct wpa_ssid {
int bssid_set;
/**
+ * go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set
+ */
+ u8 go_p2p_dev_addr[ETH_ALEN];
+
+ /**
* psk - WPA pre-shared key (256 bits)
*/
u8 psk[32];
@@ -140,6 +155,14 @@ struct wpa_ssid {
char *passphrase;
/**
+ * ext_psk - PSK/passphrase name in external storage
+ *
+ * If this is set, PSK/passphrase will be fetched from external storage
+ * when requesting association with the network.
+ */
+ char *ext_psk;
+
+ /**
* pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
*/
int pairwise_cipher;
@@ -157,6 +180,12 @@ struct wpa_ssid {
int key_mgmt;
/**
+ * bg_scan_period - Background scan period in seconds, 0 to disable, or
+ * -1 to indicate no change to default driver configuration
+ */
+ int bg_scan_period;
+
+ /**
* proto - Bitfield of allowed protocols, WPA_PROTO_*
*/
int proto;
@@ -213,13 +242,18 @@ struct wpa_ssid {
*
* This field can be used to enable proactive key caching which is also
* known as opportunistic PMKSA caching for WPA2. This is disabled (0)
- * by default. Enable by setting this to 1.
+ * by default unless default value is changed with the global okc=1
+ * parameter. Enable by setting this to 1.
*
* Proactive key caching is used to make supplicant assume that the APs
* are using the same PMK and generate PMKSA cache entries without
* doing RSN pre-authentication. This requires support from the AP side
* and is normally used with wireless switches that co-locate the
* authenticator.
+ *
+ * Internally, special value -1 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
*/
int proactive_key_caching;
@@ -281,12 +315,13 @@ struct wpa_ssid {
* 4 = P2P Group Formation (used internally; not in configuration
* files)
*
- * Note: IBSS can only be used with key_mgmt NONE (plaintext and
- * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
- * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
- * following network block options: proto=WPA, key_mgmt=WPA-NONE,
- * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
- * be set (either directly or using ASCII passphrase).
+ * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
+ * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
+ * (fixed group key TKIP/CCMP) is available for backwards compatibility,
+ * but its use is deprecated. WPA-None requires following network block
+ * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or
+ * CCMP, but not both), and psk must also be set (either directly or
+ * using ASCII passphrase).
*/
enum wpas_mode {
WPAS_MODE_INFRA = 0,
@@ -308,6 +343,14 @@ struct wpa_ssid {
int disabled;
/**
+ * disabled_for_connect - Whether this network was temporarily disabled
+ *
+ * This flag is used to reenable all the temporarily disabled networks
+ * after either the success or failure of a WPS connection.
+ */
+ int disabled_for_connect;
+
+ /**
* peerkey - Whether PeerKey handshake for direct links is allowed
*
* This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
@@ -333,6 +376,12 @@ struct wpa_ssid {
*
* This value is used to configure policy for management frame
* protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+ * This is disabled by default unless the default value has been changed
+ * with the global pmf=1/2 parameter.
+ *
+ * Internally, special value 3 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
*/
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
@@ -349,6 +398,10 @@ struct wpa_ssid {
*/
int frequency;
+ int ht40;
+
+ int vht;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -377,6 +430,20 @@ struct wpa_ssid {
char *bgscan;
/**
+ * ignore_broadcast_ssid - Hide SSID in AP mode
+ *
+ * Send empty SSID in beacons and ignore probe request frames that do
+ * not specify full SSID, i.e., require stations to know SSID.
+ * default: disabled (0)
+ * 1 = send empty (length=0) SSID in beacon and ignore probe request
+ * for broadcast SSID
+ * 2 = clear SSID (ASCII 0), but keep the original length (this may be
+ * required with some clients that do not support empty SSID) and
+ * ignore probe requests for broadcast SSID
+ */
+ int ignore_broadcast_ssid;
+
+ /**
* freq_list - Array of allowed frequencies or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -405,6 +472,11 @@ struct wpa_ssid {
#endif /* P2P_MAX_STORED_CLIENTS */
/**
+ * psk_list - Per-client PSKs (struct psk_list_entry)
+ */
+ struct dl_list psk_list;
+
+ /**
* p2p_group - Network generated as a P2P group (used internally)
*/
int p2p_group;
@@ -426,6 +498,129 @@ struct wpa_ssid {
* WPS or similar so that they may be exported.
*/
int export_keys;
+
+#ifdef CONFIG_HT_OVERRIDES
+ /**
+ * disable_ht - Disable HT (IEEE 802.11n) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_ht;
+
+ /**
+ * disable_ht40 - Disable HT40 for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_ht40;
+
+ /**
+ * disable_sgi - Disable SGI (Short Guard Interval) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_sgi;
+
+ /**
+ * disable_max_amsdu - Disable MAX A-MSDU
+ *
+ * A-MDSU will be 3839 bytes when disabled, or 7935
+ * when enabled (assuming it is otherwise supported)
+ * -1 (default) means do not apply any settings to the kernel.
+ */
+ int disable_max_amsdu;
+
+ /**
+ * ampdu_factor - Maximum A-MPDU Length Exponent
+ *
+ * Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+ */
+ int ampdu_factor;
+
+ /**
+ * ampdu_density - Minimum A-MPDU Start Spacing
+ *
+ * Value: 0-7, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+ */
+ int ampdu_density;
+
+ /**
+ * ht_mcs - Allowed HT-MCS rates, in ASCII hex: ffff0000...
+ *
+ * By default (empty string): Use whatever the OS has configured.
+ */
+ char *ht_mcs;
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_VHT_OVERRIDES
+ /**
+ * disable_vht - Disable VHT (IEEE 802.11ac) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_vht;
+
+ /**
+ * vht_capa - VHT capabilities to use
+ */
+ unsigned int vht_capa;
+
+ /**
+ * vht_capa_mask - mask for VHT capabilities
+ */
+ unsigned int vht_capa_mask;
+
+ int vht_rx_mcs_nss_1, vht_rx_mcs_nss_2,
+ vht_rx_mcs_nss_3, vht_rx_mcs_nss_4,
+ vht_rx_mcs_nss_5, vht_rx_mcs_nss_6,
+ vht_rx_mcs_nss_7, vht_rx_mcs_nss_8;
+ int vht_tx_mcs_nss_1, vht_tx_mcs_nss_2,
+ vht_tx_mcs_nss_3, vht_tx_mcs_nss_4,
+ vht_tx_mcs_nss_5, vht_tx_mcs_nss_6,
+ vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ /**
+ * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+ *
+ * This timeout value is used in AP mode to clean up inactive stations.
+ * By default: 300 seconds.
+ */
+ int ap_max_inactivity;
+
+ /**
+ * dtim_period - DTIM period in Beacon intervals
+ * By default: 2
+ */
+ int dtim_period;
+
+ /**
+ * beacon_int - Beacon interval (default: 100 TU)
+ */
+ int beacon_int;
+
+ /**
+ * auth_failures - Number of consecutive authentication failures
+ */
+ unsigned int auth_failures;
+
+ /**
+ * disabled_until - Network block disabled until this time if non-zero
+ */
+ struct os_reltime disabled_until;
+
+ /**
+ * parent_cred - Pointer to parent wpa_cred entry
+ *
+ * This pointer can be used to delete temporary networks when a wpa_cred
+ * that was used to create them is removed. This pointer should not be
+ * dereferences since it may not be updated in all cases.
+ */
+ void *parent_cred;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index ea3a2ac..00a1004 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -2,14 +2,8 @@
* WPA Supplicant / Configuration backend: Windows registry
* Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This file implements a configuration backend for Windows registry. All the
* configuration information is stored in the registry and the format for
@@ -208,6 +202,7 @@ static int wpa_config_read_global_os_version(struct wpa_config *config,
static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
{
int errors = 0;
+ int val;
wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
@@ -277,6 +272,10 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
(int *) &config->disassoc_low_ack);
+ wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+ wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+ config->pmf = val;
+
return errors ? -1 : 0;
}
@@ -303,6 +302,7 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
RegCloseKey(nhk);
return NULL;
}
+ dl_list_init(&ssid->psk_list);
ssid->id = id;
wpa_config_set_network_defaults(ssid);
@@ -350,15 +350,6 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
wpa_config_update_psk(ssid);
}
- if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_PSK_SHA256)) &&
- !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
- "but no PSK configured for network '" TSTR "'.",
- netw);
- errors++;
- }
-
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
@@ -444,7 +435,7 @@ static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
}
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
TCHAR buf[256];
int errors = 0;
@@ -452,7 +443,12 @@ struct wpa_config * wpa_config_read(const char *name)
HKEY hk;
LONG ret;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
@@ -624,6 +620,12 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
config->disassoc_low_ack, 0);
+ wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+ wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+
+ wpa_config_write_reg_dword(hk, TEXT("external_sim"),
+ config->external_sim, 0);
+
return 0;
}
@@ -919,11 +921,13 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
- INT(proactive_key_caching);
+ write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+ -1);
INT(disabled);
INT(peerkey);
#ifdef CONFIG_IEEE80211W
- INT(ieee80211w);
+ write_int(netw, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 24065e0..9a3cbea 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,23 +1,19 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/uuid.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -34,15 +30,16 @@
#include "ap.h"
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
#include "ctrl_iface.h"
#include "interworking.h"
#include "blacklist.h"
-#include "wpas_glue.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
+#include "autoscan.h"
+#include "wnm_sta.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
@@ -50,6 +47,266 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
char *buf, int len);
+static int pno_start(struct wpa_supplicant *wpa_s)
+{
+ int ret, interval;
+ size_t i, num_ssid;
+ struct wpa_ssid *ssid;
+ struct wpa_driver_scan_params params;
+
+ if (wpa_s->pno || wpa_s->pno_sched_pending)
+ return 0;
+
+ if ((wpa_s->wpa_state > WPA_SCANNING) &&
+ (wpa_s->wpa_state <= WPA_COMPLETED)) {
+ wpa_printf(MSG_ERROR, "PNO: In assoc process");
+ return -EAGAIN;
+ }
+
+ if (wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_supplicant_cancel_scan(wpa_s);
+ if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Schedule PNO on completion of "
+ "ongoing sched scan");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->pno_sched_pending = 1;
+ return 0;
+ }
+ }
+
+ os_memset(&params, 0, sizeof(params));
+
+ num_ssid = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid))
+ num_ssid++;
+ ssid = ssid->next;
+ }
+ if (num_ssid > WPAS_MAX_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;
+ }
+
+ if (num_ssid == 0) {
+ wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+ return -1;
+ }
+
+ params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
+ num_ssid);
+ if (params.filter_ssids == NULL)
+ return -1;
+ i = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ params.ssids[i].ssid = ssid->ssid;
+ params.ssids[i].ssid_len = ssid->ssid_len;
+ params.num_ssids++;
+ os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+ ssid->ssid_len);
+ params.filter_ssids[i].ssid_len = ssid->ssid_len;
+ params.num_filter_ssids++;
+ i++;
+ if (i == num_ssid)
+ break;
+ }
+ ssid = ssid->next;
+ }
+
+ 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;
+
+ ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
+ os_free(params.filter_ssids);
+ if (ret == 0)
+ wpa_s->pno = 1;
+ return ret;
+}
+
+
+static int pno_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret = 0;
+
+ if (wpa_s->pno || wpa_s->sched_scanning) {
+ wpa_s->pno = 0;
+ ret = wpa_supplicant_stop_sched_scan(wpa_s);
+ }
+
+ wpa_s->pno_sched_pending = 0;
+
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return ret;
+}
+
+
+static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
+{
+ char *pos;
+ u8 addr[ETH_ALEN], *filter = NULL, *n;
+ size_t count = 0;
+
+ pos = val;
+ while (pos) {
+ if (*pos == '\0')
+ break;
+ if (hwaddr_aton(pos, addr)) {
+ os_free(filter);
+ return -1;
+ }
+ n = os_realloc_array(filter, count + 1, ETH_ALEN);
+ if (n == NULL) {
+ os_free(filter);
+ return -1;
+ }
+ filter = n;
+ os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
+ count++;
+
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
+ os_free(wpa_s->bssid_filter);
+ wpa_s->bssid_filter = filter;
+ wpa_s->bssid_filter_count = count;
+
+ return 0;
+}
+
+
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+ char *pos;
+ u8 addr[ETH_ALEN], *bssid = NULL, *n;
+ struct wpa_ssid_value *ssid = NULL, *ns;
+ size_t count = 0, ssid_count = 0;
+ struct wpa_ssid *c;
+
+ /*
+ * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
+ * SSID_SPEC ::= ssid <SSID_HEX>
+ * BSSID_SPEC ::= bssid <BSSID_HEX>
+ */
+
+ pos = val;
+ while (pos) {
+ if (*pos == '\0')
+ break;
+ if (os_strncmp(pos, "bssid ", 6) == 0) {
+ int res;
+ pos += 6;
+ res = hwaddr_aton2(pos, addr);
+ if (res < 0) {
+ os_free(ssid);
+ os_free(bssid);
+ wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+ "BSSID value '%s'", pos);
+ return -1;
+ }
+ pos += res;
+ n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+ if (n == NULL) {
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+ bssid = n;
+ os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+ count++;
+ } else if (os_strncmp(pos, "ssid ", 5) == 0) {
+ char *end;
+ pos += 5;
+
+ end = pos;
+ while (*end) {
+ if (*end == '\0' || *end == ' ')
+ break;
+ end++;
+ }
+
+ ns = os_realloc_array(ssid, ssid_count + 1,
+ sizeof(struct wpa_ssid_value));
+ if (ns == NULL) {
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+ ssid = ns;
+
+ if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+ hexstr2bin(pos, ssid[ssid_count].ssid,
+ (end - pos) / 2) < 0) {
+ os_free(ssid);
+ os_free(bssid);
+ wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+ "SSID value '%s'", pos);
+ return -1;
+ }
+ ssid[ssid_count].ssid_len = (end - pos) / 2;
+ wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+ ssid[ssid_count].ssid,
+ ssid[ssid_count].ssid_len);
+ ssid_count++;
+ pos = end;
+ } else {
+ wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+ "'%s'", pos);
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = bssid;
+ wpa_s->disallow_aps_bssid_count = count;
+
+ wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = ssid;
+ wpa_s->disallow_aps_ssid_count = ssid_count;
+
+ if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+ return 0;
+
+ c = wpa_s->current_ssid;
+ if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+ return 0;
+
+ if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+ !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+ "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_s->reassociate = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -107,17 +364,21 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wps_testing_dummy_cred = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+ wps_corrupt_pkhash = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+ wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
} else if (os_strcasecmp(cmd, "ampdu") == 0) {
if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
ret = -1;
+#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 */
-#ifdef CONFIG_TDLS
} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
int disabled = atoi(value);
wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
@@ -128,6 +389,65 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = -1;
wpa_tdls_enable(wpa_s->wpa, !disabled);
#endif /* CONFIG_TDLS */
+ } else if (os_strcasecmp(cmd, "pno") == 0) {
+ if (atoi(value))
+ ret = pno_start(wpa_s);
+ else
+ ret = pno_stop(wpa_s);
+ } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
+ int disabled = atoi(value);
+ if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
+ ret = -1;
+ else if (disabled)
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+ } else if (os_strcasecmp(cmd, "uapsd") == 0) {
+ if (os_strcmp(value, "disable") == 0)
+ wpa_s->set_sta_uapsd = 0;
+ else {
+ int be, bk, vi, vo;
+ char *pos;
+ /* format: BE,BK,VI,VO;max SP Length */
+ be = atoi(value);
+ pos = os_strchr(value, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ bk = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vi = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vo = atoi(pos);
+ /* ignore max SP Length for now */
+
+ wpa_s->set_sta_uapsd = 1;
+ wpa_s->sta_uapsd = 0;
+ if (be)
+ wpa_s->sta_uapsd |= BIT(0);
+ if (bk)
+ wpa_s->sta_uapsd |= BIT(1);
+ if (vi)
+ wpa_s->sta_uapsd |= BIT(2);
+ if (vo)
+ wpa_s->sta_uapsd |= BIT(3);
+ }
+ } else if (os_strcasecmp(cmd, "ps") == 0) {
+ ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(wpa_s->global, !!atoi(value));
+#endif /* CONFIG_WIFI_DISPLAY */
+ } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
+ ret = set_bssid_filter(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+ ret = set_disallow_aps(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
+ wpa_s->no_keep_alive = !!atoi(value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -142,18 +462,38 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
char *cmd, char *buf, size_t buflen)
{
- int res;
+ int res = -1;
wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
if (os_strcmp(cmd, "version") == 0) {
res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+ } else if (os_strcasecmp(cmd, "country") == 0) {
+ if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
+ res = os_snprintf(buf, buflen, "%c%c",
+ wpa_s->conf->country[0],
+ wpa_s->conf->country[1]);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ res = os_snprintf(buf, buflen, "%d",
+ wpa_s->global->wifi_display);
if (res < 0 || (unsigned int) res >= buflen)
return -1;
return res;
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_TESTING_GET_GTK
+ } else if (os_strcmp(cmd, "gtk") == 0) {
+ if (wpa_s->last_gtk_len == 0)
+ return -1;
+ res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
+ wpa_s->last_gtk_len);
+ return res;
+#endif /* CONFIG_TESTING_GET_GTK */
}
- return -1;
+ if (res < 0 || (unsigned int) res >= buflen)
+ return -1;
+ return res;
}
@@ -242,13 +582,16 @@ static int wpa_supplicant_ctrl_iface_tdls_setup(
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
MAC2STR(peer));
- ret = wpa_tdls_reneg(wpa_s->wpa, peer);
- if (ret) {
- if (wpa_tdls_is_external_setup(wpa_s->wpa))
- ret = wpa_tdls_start(wpa_s->wpa, peer);
- else
- ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
- }
+ if ((wpa_s->conf->tdls_external_control) &&
+ wpa_tdls_is_external_setup(wpa_s->wpa))
+ return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+ wpa_tdls_remove(wpa_s->wpa, peer);
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
return ret;
}
@@ -258,6 +601,7 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown(
struct wpa_supplicant *wpa_s, char *addr)
{
u8 peer[ETH_ALEN];
+ int ret;
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
@@ -268,8 +612,18 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown(
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
MAC2STR(peer));
- return wpa_tdls_teardown_link(wpa_s->wpa, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ if ((wpa_s->conf->tdls_external_control) &&
+ wpa_tdls_is_external_setup(wpa_s->wpa))
+ return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_teardown_link(
+ wpa_s->wpa, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ return ret;
}
#endif /* CONFIG_TDLS */
@@ -365,9 +719,21 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
+ if (wpa_s->ap_iface) {
+ int timeout = 0;
+ char *pos;
+
+ if (pin) {
+ pos = os_strchr(pin, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ timeout = atoi(pos);
+ }
+ }
+
return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
- buf, buflen);
+ buf, buflen, timeout);
+ }
#endif /* CONFIG_AP */
if (pin) {
@@ -439,29 +805,456 @@ static int wpa_supplicant_ctrl_iface_wps_check_pin(
}
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
char *cmd)
{
- char *path, *method, *name;
+ u8 bssid[ETH_ALEN], *_bssid = bssid;
+
+ if (cmd == NULL || cmd[0] == '\0')
+ _bssid = NULL;
+ else if (hwaddr_aton(cmd, bssid))
+ return -1;
+
+ return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
+ 0, 0);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos)
+ *pos++ = '\0';
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
- path = os_strchr(cmd, ' ');
- if (path == NULL)
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
return -1;
- *path++ = '\0';
- method = os_strchr(path, ' ');
- if (method == NULL)
+ buf = wpas_wps_nfc_token(wpa_s, ndef);
+ if (buf == NULL)
return -1;
- *method++ = '\0';
- name = os_strchr(method, ' ');
- if (name != NULL)
- *name++ = '\0';
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
- return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
+ return res;
}
-#endif /* CONFIG_WPS_OOB */
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
+ struct wpa_supplicant *wpa_s, char *pos)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+ char *freq;
+ int forced_freq = 0;
+
+ freq = strstr(pos, " freq=");
+ if (freq) {
+ *freq = '\0';
+ freq += 6;
+ forced_freq = atoi(freq);
+ }
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
+ return -1;
+ }
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ if (!ndef)
+ return -1;
+ return wpas_ctrl_nfc_get_handover_req_wps(
+ wpa_s, reply, max_len, ndef);
+ }
+
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_p2p(
+ wpa_s, reply, max_len, ndef);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef, int cr, char *uuid)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef, int tag)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos, *pos2;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ *pos2++ = '\0';
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ if (!ndef)
+ return -1;
+ return wpas_ctrl_nfc_get_handover_sel_wps(
+ wpa_s, reply, max_len, ndef,
+ os_strcmp(pos, "WPS-CR") == 0, pos2);
+ }
+
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 0);
+ }
+
+ if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 1);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *req, *sel;
+ int ret;
+ char *pos, *role, *type, *pos2;
+ char *freq;
+ int forced_freq = 0;
+
+ freq = strstr(cmd, " freq=");
+ if (freq) {
+ *freq = '\0';
+ freq += 6;
+ forced_freq = atoi(freq);
+ }
+
+ role = cmd;
+ pos = os_strchr(role, ' ');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
+ return -1;
+ }
+ *pos++ = '\0';
+
+ type = pos;
+ pos = os_strchr(type, ' ');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
+ return -1;
+ }
+ *pos++ = '\0';
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
+ return -1;
+ }
+ *pos2++ = '\0';
+
+ len = os_strlen(pos);
+ if (len & 0x01) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
+ return -1;
+ }
+ len /= 2;
+
+ req = wpabuf_alloc(len);
+ if (req == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
+ return -1;
+ }
+ if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
+ wpabuf_free(req);
+ return -1;
+ }
+
+ len = os_strlen(pos2);
+ if (len & 0x01) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
+ wpabuf_free(req);
+ return -1;
+ }
+ len /= 2;
+
+ sel = wpabuf_alloc(len);
+ if (sel == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
+ wpabuf_free(req);
+ return -1;
+ }
+ if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
+ wpabuf_free(req);
+ wpabuf_free(sel);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
+ role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
+
+ if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
+ ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
+ {
+ ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
+ if (ret < 0)
+ ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
+ } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
+ forced_freq);
+ } else {
+ wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+ "reported: role=%s type=%s", role, type);
+ ret = -1;
+ }
+ wpabuf_free(req);
+ wpabuf_free(sel);
+
+ if (ret)
+ wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
+
+ return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
@@ -660,6 +1453,43 @@ static int wpa_supplicant_ctrl_iface_wps_er_config(
ap.key_hex = new_key;
return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
}
+
+
+#ifdef CONFIG_WPS_NFC
+static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+ char *uuid;
+
+ uuid = os_strchr(cmd, ' ');
+ if (uuid == NULL)
+ return -1;
+ *uuid++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS_ER */
#endif /* CONFIG_WPS */
@@ -728,9 +1558,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
char *pos, *end, tmp[30];
- int res, verbose, ret;
+ int res, verbose, wps, ret;
+ if (os_strcmp(params, "-DRIVER") == 0)
+ return wpa_drv_status(wpa_s, buf, buflen);
verbose = os_strcmp(params, "-VERBOSE") == 0;
+ wps = os_strcmp(params, "-WPS") == 0;
pos = buf;
end = buf + buflen;
if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
@@ -759,6 +1592,17 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
return pos - buf;
pos += ret;
+ if (wps && ssid->passphrase &&
+ wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
+ (ssid->mode == WPAS_MODE_AP ||
+ ssid->mode == WPAS_MODE_P2P_GO)) {
+ ret = os_snprintf(pos, end - pos,
+ "passphrase=%s\n",
+ ssid->passphrase);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (ssid->id_str) {
ret = os_snprintf(pos, end - pos,
"id_str=%s\n",
@@ -808,6 +1652,19 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_AP */
pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
}
+#ifdef CONFIG_SAE
+ if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
+#ifdef CONFIG_AP
+ !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+ wpa_s->sme.sae.state == SAE_ACCEPTED) {
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
+ wpa_s->sme.sae.group);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
wpa_supplicant_state_txt(wpa_s->wpa_state));
if (ret < 0 || ret >= end - pos)
@@ -838,6 +1695,60 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
return pos - buf;
pos += ret;
+#ifdef CONFIG_HS20
+ if (wpa_s->current_bss &&
+ wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+ wpa_s->wpa_proto == WPA_PROTO_RSN &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+ ret = os_snprintf(pos, end - pos, "hs20=1\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (wpa_s->current_ssid) {
+ struct wpa_cred *cred;
+ char *type;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ size_t i;
+
+ if (wpa_s->current_ssid->parent_cred != cred)
+ continue;
+
+ for (i = 0; cred->domain && i < cred->num_domain; i++) {
+ ret = os_snprintf(pos, end - pos,
+ "home_sp=%s\n",
+ cred->domain[i]);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (wpa_s->current_bss == NULL ||
+ wpa_s->current_bss->anqp == NULL)
+ res = -1;
+ else
+ res = interworking_home_sp_cred(
+ wpa_s, cred,
+ wpa_s->current_bss->anqp->domain_name);
+ if (res > 0)
+ type = "home";
+ else if (res == 0)
+ type = "roaming";
+ else
+ type = "unknown";
+
+ ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ break;
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
@@ -850,6 +1761,37 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
if (res >= 0)
pos += res;
+#ifdef CONFIG_WPS
+ {
+ char uuid_str[100];
+ uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
+ ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef ANDROID
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
+ "id=%d state=%d BSSID=" MACSTR " SSID=%s",
+ wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
+ wpa_s->wpa_state,
+ MAC2STR(wpa_s->bssid),
+ wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
+ wpa_ssid_txt(wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len) : "");
+ if (wpa_s->wpa_state == WPA_COMPLETED) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
+ "- connection to " MACSTR
+ " completed %s [id=%d id_str=%s]",
+ MAC2STR(wpa_s->bssid), "(auth)",
+ ssid ? ssid->id : -1,
+ ssid && ssid->id_str ? ssid->id_str : "");
+ }
+#endif /* ANDROID */
+
return pos - buf;
}
@@ -941,9 +1883,6 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
}
-extern int wpa_debug_level;
-extern int wpa_debug_timestamp;
-
static const char * debug_level_str(int level)
{
switch (level) {
@@ -1066,10 +2005,12 @@ static int wpa_supplicant_ctrl_iface_list_networks(
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- ret = os_snprintf(pos, end - pos, "\t%s%s%s",
+ ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
ssid == wpa_s->current_ssid ?
"[CURRENT]" : "",
ssid->disabled ? "[DISABLED]" : "",
+ ssid->disabled_until.sec ?
+ "[TEMP-DISABLED]" : "",
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
"");
if (ret < 0 || ret >= end - pos)
@@ -1089,47 +2030,15 @@ static int wpa_supplicant_ctrl_iface_list_networks(
static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
{
- int first = 1, ret;
+ int ret;
ret = os_snprintf(pos, end - pos, "-");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- if (cipher & WPA_CIPHER_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
+ ret = wpa_write_ciphers(pos, end, cipher, "+");
+ if (ret < 0)
+ return pos;
+ pos += ret;
return pos;
}
@@ -1284,6 +2193,8 @@ static int wpa_supplicant_ctrl_iface_scan_result(
const u8 *ie, *ie2, *p2p;
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p)
+ p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
0)
@@ -1328,6 +2239,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
return -1;
pos += ret;
}
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
+ ret = os_snprintf(pos, end - pos, "[HS20]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -1429,6 +2348,11 @@ static int wpa_supplicant_ctrl_iface_enable_network(
"ENABLE_NETWORK with persistent P2P group");
return -1;
}
+
+ if (os_strstr(cmd, " no-connect")) {
+ ssid->disabled = 0;
+ return 0;
+ }
}
wpa_supplicant_enable_network(wpa_s, ssid);
@@ -1498,18 +2422,14 @@ static int wpa_supplicant_ctrl_iface_remove_network(
{
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- struct wpa_ssid *remove_ssid = ssid;
- id = ssid->id;
- ssid = ssid->next;
- wpas_notify_network_removed(wpa_s, remove_ssid);
- wpa_config_remove_network(wpa_s->conf, id);
- }
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
#ifdef CONFIG_SME
@@ -1517,8 +2437,16 @@ static int wpa_supplicant_ctrl_iface_remove_network(
#endif /* CONFIG_SME */
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- wpa_supplicant_disassociate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ id = ssid->id;
+ ssid = ssid->next;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
}
return 0;
}
@@ -1550,15 +2478,25 @@ static int wpa_supplicant_ctrl_iface_remove_network(
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
}
+ was_disabled = ssid->disabled;
+
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
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;
}
@@ -1600,7 +2538,9 @@ static int wpa_supplicant_ctrl_iface_set_network(
return -1;
}
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ if (os_strcmp(name, "bssid") != 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) {
/*
@@ -1665,6 +2605,174 @@ static int wpa_supplicant_ctrl_iface_get_network(
}
+static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ struct wpa_cred *cred;
+ int ret;
+
+ pos = buf;
+ end = buf + buflen;
+ ret = os_snprintf(pos, end - pos,
+ "cred id / realm / username / domain / imsi\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
+ cred->id, cred->realm ? cred->realm : "",
+ cred->username ? cred->username : "",
+ cred->domain ? cred->domain[0] : "",
+ cred->imsi ? cred->imsi : "");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ cred = cred->next;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct wpa_cred *cred;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
+
+ cred = wpa_config_add_cred(wpa_s->conf);
+ if (cred == NULL)
+ return -1;
+
+ ret = os_snprintf(buf, buflen, "%d\n", cred->id);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+}
+
+
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred)
+{
+ struct wpa_ssid *ssid;
+ char str[20];
+
+ if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+ return -1;
+ }
+
+ /* Remove any network entry created based on the removed credential */
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (ssid->parent_cred == cred) {
+ wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+ "used the removed credential", ssid->id);
+ os_snprintf(str, sizeof(str), "%d", ssid->id);
+ ssid = ssid->next;
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+ } else
+ ssid = ssid->next;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int id;
+ struct wpa_cred *cred, *prev;
+
+ /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
+ if (os_strcmp(cmd, "all") == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ }
+ return 0;
+ }
+
+ if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+ cmd + 8);
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ if (prev->domain) {
+ size_t i;
+ for (i = 0; i < prev->num_domain; i++) {
+ if (os_strcmp(prev->domain[i], cmd + 8)
+ != 0)
+ continue;
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ break;
+ }
+ }
+ }
+ return 0;
+ }
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ return wpas_ctrl_remove_cred(wpa_s, cred);
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int id;
+ struct wpa_cred *cred;
+ char *name, *value;
+
+ /* cmd: "<cred id> <variable name> <value>" */
+ name = os_strchr(cmd, ' ');
+ if (name == NULL)
+ return -1;
+ *name++ = '\0';
+
+ value = os_strchr(name, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
+ id, name);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+ (u8 *) value, os_strlen(value));
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+ id);
+ return -1;
+ }
+
+ if (wpa_config_set_cred(cred, name, value, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
+ "variable '%s'", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
#ifndef CONFIG_NO_CONFIG_WRITE
static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
{
@@ -1690,6 +2798,24 @@ static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_NO_CONFIG_WRITE */
+struct cipher_info {
+ unsigned int capa;
+ const char *name;
+ int group_only;
+};
+
+static const struct cipher_info ciphers[] = {
+ { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
+ { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
+ { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
+ { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+ { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+ { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+ { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
+ { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+};
+
+
static int ctrl_iface_get_capability_pairwise(int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
@@ -1697,6 +2823,7 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
int ret, first = 1;
char *pos, *end;
size_t len;
+ unsigned int i;
pos = buf;
end = pos + buflen;
@@ -1710,28 +2837,15 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
return len;
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+ if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ first ? "" : " ", ciphers[i].name);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
}
return pos - buf;
@@ -1745,6 +2859,7 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
int ret, first = 1;
char *pos, *end;
size_t len;
+ unsigned int i;
pos = buf;
end = pos + buflen;
@@ -1758,37 +2873,15 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
return len;
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+ if (capa->enc & ciphers[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ first ? "" : " ", ciphers[i].name);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
}
return pos - buf;
@@ -1939,6 +3032,150 @@ static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
}
+static int ctrl_iface_get_capability_modes(int res, char *strict,
+ struct wpa_driver_capa *capa,
+ char *buf, size_t buflen)
+{
+ int ret, first = 1;
+ char *pos, *end;
+ size_t len;
+
+ pos = buf;
+ end = pos + buflen;
+
+ if (res < 0) {
+ if (strict)
+ return 0;
+ len = os_strlcpy(buf, "IBSS AP", buflen);
+ if (len >= buflen)
+ return -1;
+ return len;
+ }
+
+ if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
+ ret = os_snprintf(pos, end - pos, "%sIBSS", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
+ if (capa->flags & WPA_DRIVER_FLAGS_AP) {
+ ret = os_snprintf(pos, end - pos, "%sAP", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
+ return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct hostapd_channel_data *chnl;
+ int ret, i, j;
+ char *pos, *end, *hmode;
+
+ pos = buf;
+ end = pos + buflen;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ switch (wpa_s->hw.modes[j].mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ hmode = "B";
+ break;
+ case HOSTAPD_MODE_IEEE80211G:
+ hmode = "G";
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ hmode = "A";
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ hmode = "AD";
+ break;
+ default:
+ continue;
+ }
+ ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ chnl = wpa_s->hw.modes[j].channels;
+ for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+ if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct hostapd_channel_data *chnl;
+ int ret, i, j;
+ char *pos, *end, *hmode;
+
+ pos = buf;
+ end = pos + buflen;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ switch (wpa_s->hw.modes[j].mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ hmode = "B";
+ break;
+ case HOSTAPD_MODE_IEEE80211G:
+ hmode = "G";
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ hmode = "A";
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ hmode = "AD";
+ break;
+ default:
+ continue;
+ }
+ ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
+ hmode);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ chnl = wpa_s->hw.modes[j].channels;
+ for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+ if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ ret = os_snprintf(pos, end - pos, " %d = %d MHz%s\n",
+ chnl[i].chan, chnl[i].freq,
+ chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
+ " (NO_IBSS)" : "");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_ctrl_iface_get_capability(
struct wpa_supplicant *wpa_s, const char *_field, char *buf,
size_t buflen)
@@ -1989,6 +3226,16 @@ static int wpa_supplicant_ctrl_iface_get_capability(
return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
buf, buflen);
+ if (os_strcmp(field, "modes") == 0)
+ return ctrl_iface_get_capability_modes(res, strict, &capa,
+ buf, buflen);
+
+ if (os_strcmp(field, "channels") == 0)
+ return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
+
+ if (os_strcmp(field, "freq") == 0)
+ return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -2031,6 +3278,261 @@ static char * anqp_add_hex(char *pos, char *end, const char *title,
#endif /* CONFIG_INTERWORKING */
+static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ unsigned long mask, char *buf, size_t buflen)
+{
+ size_t i;
+ int ret;
+ char *pos, *end;
+ const u8 *ie, *ie2;
+
+ pos = buf;
+ end = buf + buflen;
+
+ if (mask & WPA_BSS_MASK_ID) {
+ ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_BSSID) {
+ ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+ MAC2STR(bss->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_FREQ) {
+ ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_BEACON_INT) {
+ ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
+ bss->beacon_int);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_CAPABILITIES) {
+ ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
+ bss->caps);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_QUAL) {
+ ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_NOISE) {
+ ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_LEVEL) {
+ ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_TSF) {
+ ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
+ (unsigned long long) bss->tsf);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_AGE) {
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ ret = os_snprintf(pos, end - pos, "age=%d\n",
+ (int) (now.sec - bss->last_update.sec));
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_IE) {
+ ret = os_snprintf(pos, end - pos, "ie=");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+
+ ie = (const u8 *) (bss + 1);
+ for (i = 0; i < bss->ie_len; i++) {
+ ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_FLAGS) {
+ ret = os_snprintf(pos, end - pos, "flags=");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ if (ie)
+ pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
+ 2 + ie[1]);
+ ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (ie2)
+ pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
+ 2 + ie2[1]);
+ pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
+ if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+ ret = os_snprintf(pos, end - pos, "[WEP]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+ if (bss->caps & IEEE80211_CAP_IBSS) {
+ ret = os_snprintf(pos, end - pos, "[IBSS]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+ if (bss->caps & IEEE80211_CAP_ESS) {
+ ret = os_snprintf(pos, end - pos, "[ESS]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+ if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "[P2P]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "[HS20]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_SSID) {
+ ret = os_snprintf(pos, end - pos, "ssid=%s\n",
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+#ifdef CONFIG_WPS
+ if (mask & WPA_BSS_MASK_WPS_SCAN) {
+ ie = (const u8 *) (bss + 1);
+ ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+ 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)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
+ struct wpabuf *wfd;
+ ie = (const u8 *) (bss + 1);
+ wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
+ WFD_IE_VENDOR_TYPE);
+ if (wfd) {
+ ret = os_snprintf(pos, end - pos, "wfd_subelems=");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(wfd),
+ wpabuf_len(wfd));
+ wpabuf_free(wfd);
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_INTERWORKING
+ if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+ struct wpa_bss_anqp *anqp = bss->anqp;
+ pos = anqp_add_hex(pos, end, "anqp_venue_name",
+ anqp->venue_name);
+ pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
+ anqp->network_auth_type);
+ pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
+ anqp->roaming_consortium);
+ pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
+ anqp->ip_addr_type_availability);
+ pos = anqp_add_hex(pos, end, "anqp_nai_realm",
+ anqp->nai_realm);
+ pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
+ pos = anqp_add_hex(pos, end, "anqp_domain_name",
+ anqp->domain_name);
+#ifdef CONFIG_HS20
+ pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
+ anqp->hs20_operator_friendly_name);
+ pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
+ anqp->hs20_wan_metrics);
+ pos = anqp_add_hex(pos, end, "hs20_connection_capability",
+ anqp->hs20_connection_capability);
+#endif /* CONFIG_HS20 */
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ if (mask & WPA_BSS_MASK_DELIM) {
+ ret = os_snprintf(pos, end - pos, "====\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
const char *cmd, char *buf,
size_t buflen)
@@ -2038,12 +3540,64 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
size_t i;
struct wpa_bss *bss;
- int ret;
- char *pos, *end;
- const u8 *ie, *ie2;
+ struct wpa_bss *bsslast = NULL;
+ struct dl_list *next;
+ int ret = 0;
+ int len;
+ char *ctmp;
+ unsigned long mask = WPA_BSS_MASK_ALL;
+
+ if (os_strncmp(cmd, "RANGE=", 6) == 0) {
+ if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
+ bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
+ list_id);
+ bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
+ list_id);
+ } else { /* N1-N2 */
+ unsigned int id1, id2;
+
+ if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
+ wpa_printf(MSG_INFO, "Wrong BSS range "
+ "format");
+ return 0;
+ }
- if (os_strcmp(cmd, "FIRST") == 0)
- bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
+ if (*(cmd + 6) == '-')
+ id1 = 0;
+ else
+ id1 = atoi(cmd + 6);
+ ctmp++;
+ if (*ctmp >= '0' && *ctmp <= '9')
+ id2 = atoi(ctmp);
+ else
+ id2 = (unsigned int) -1;
+ bss = wpa_bss_get_id_range(wpa_s, id1, id2);
+ if (id2 == (unsigned int) -1)
+ bsslast = dl_list_last(&wpa_s->bss_id,
+ struct wpa_bss,
+ list_id);
+ else {
+ bsslast = wpa_bss_get_id(wpa_s, id2);
+ if (bsslast == NULL && bss && id2 > id1) {
+ struct wpa_bss *tmp = bss;
+ for (;;) {
+ next = tmp->list_id.next;
+ if (next == &wpa_s->bss_id)
+ break;
+ tmp = dl_list_entry(
+ next, struct wpa_bss,
+ list_id);
+ if (tmp->id > id2)
+ break;
+ bsslast = tmp;
+ }
+ }
+ }
+ }
+ } else if (os_strncmp(cmd, "FIRST", 5) == 0)
+ bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+ else if (os_strncmp(cmd, "LAST", 4) == 0)
+ bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
else if (os_strncmp(cmd, "ID-", 3) == 0) {
i = atoi(cmd + 3);
bss = wpa_bss_get_id(wpa_s, i);
@@ -2051,7 +3605,7 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
i = atoi(cmd + 5);
bss = wpa_bss_get_id(wpa_s, i);
if (bss) {
- struct dl_list *next = bss->list_id.next;
+ next = bss->list_id.next;
if (next == &wpa_s->bss_id)
bss = NULL;
else
@@ -2080,122 +3634,36 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
}
}
- if (bss == NULL)
- return 0;
-
- pos = buf;
- end = buf + buflen;
- ret = os_snprintf(pos, end - pos,
- "id=%u\n"
- "bssid=" MACSTR "\n"
- "freq=%d\n"
- "beacon_int=%d\n"
- "capabilities=0x%04x\n"
- "qual=%d\n"
- "noise=%d\n"
- "level=%d\n"
- "tsf=%016llu\n"
- "ie=",
- bss->id,
- MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
- bss->caps, bss->qual, bss->noise, bss->level,
- (unsigned long long) bss->tsf);
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-
- ie = (const u8 *) (bss + 1);
- for (i = 0; i < bss->ie_len; i++) {
- ret = os_snprintf(pos, end - pos, "%02x", *ie++);
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
-
- ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-
- ret = os_snprintf(pos, end - pos, "flags=");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-
- ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
- if (ie)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
- ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (ie2)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
- pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
- if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
- ret = os_snprintf(pos, end - pos, "[WEP]");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
+ if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
+ mask = strtoul(ctmp + 5, NULL, 0x10);
+ if (mask == 0)
+ mask = WPA_BSS_MASK_ALL;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- ret = os_snprintf(pos, end - pos, "[IBSS]");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (bss->caps & IEEE80211_CAP_ESS) {
- ret = os_snprintf(pos, end - pos, "[ESS]");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
- ret = os_snprintf(pos, end - pos, "[P2P]");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
-
- ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-
- ret = os_snprintf(pos, end - pos, "ssid=%s\n",
- wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-
-#ifdef CONFIG_WPS
- ie = (const u8 *) (bss + 1);
- ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_P2P
- ie = (const u8 *) (bss + 1);
- ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-#endif /* CONFIG_P2P */
+ if (bss == NULL)
+ return 0;
-#ifdef CONFIG_INTERWORKING
- pos = anqp_add_hex(pos, end, "anqp_venue_name", bss->anqp_venue_name);
- pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
- bss->anqp_network_auth_type);
- pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
- bss->anqp_roaming_consortium);
- pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
- bss->anqp_ip_addr_type_availability);
- pos = anqp_add_hex(pos, end, "anqp_nai_realm", bss->anqp_nai_realm);
- pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
- pos = anqp_add_hex(pos, end, "anqp_domain_name",
- bss->anqp_domain_name);
-#endif /* CONFIG_INTERWORKING */
+ if (bsslast == NULL)
+ bsslast = bss;
+ do {
+ len = print_bss_info(wpa_s, bss, mask, buf, buflen);
+ ret += len;
+ buf += len;
+ buflen -= len;
+ if (bss == bsslast) {
+ if ((mask & WPA_BSS_MASK_DELIM) && len &&
+ (bss == dl_list_last(&wpa_s->bss_id,
+ struct wpa_bss, list_id)))
+ os_snprintf(buf - 5, 5, "####\n");
+ break;
+ }
+ next = bss->list_id.next;
+ if (next == &wpa_s->bss_id)
+ break;
+ bss = dl_list_entry(next, struct wpa_bss, list_id);
+ } while (bss && len);
- return pos - buf;
+ return ret;
}
@@ -2211,10 +3679,7 @@ static int wpa_supplicant_ctrl_iface_scan_interval(
struct wpa_supplicant *wpa_s, char *cmd)
{
int scan_int = atoi(cmd);
- if (scan_int < 0)
- return -1;
- wpa_s->scan_interval = scan_int;
- return 0;
+ return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
}
@@ -2234,6 +3699,19 @@ static int wpa_supplicant_ctrl_iface_bss_expire_count(
}
+static int wpa_supplicant_ctrl_iface_bss_flush(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int flush_age = atoi(cmd);
+
+ if (flush_age == 0)
+ wpa_bss_flush(wpa_s);
+ else
+ wpa_bss_flush_by_age(wpa_s, flush_age);
+ return 0;
+}
+
+
static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
@@ -2275,7 +3753,13 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+ "configuration known for the target AP");
+ return -1;
+ }
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
if (!bss) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
"from BSS table");
@@ -2287,12 +3771,6 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
* allow roaming to other networks
*/
- if (!ssid) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
- "configuration known for the target AP");
- return -1;
- }
-
wpa_s->reassociate = 1;
wpa_supplicant_connect(wpa_s, bss, ssid);
@@ -2307,7 +3785,9 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
unsigned int timeout = atoi(cmd);
enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+ u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
char *pos;
+ unsigned int search_delay;
if (os_strstr(cmd, "type=social"))
type = P2P_FIND_ONLY_SOCIAL;
@@ -2322,7 +3802,23 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
_dev_id = dev_id;
}
- return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id);
+ pos = os_strstr(cmd, "dev_type=");
+ if (pos) {
+ pos += 9;
+ if (wps_dev_type_str2bin(pos, dev_type) < 0)
+ return -1;
+ _dev_type = dev_type;
+ }
+
+ pos = os_strstr(cmd, "delay=");
+ if (pos) {
+ pos += 6;
+ search_delay = atoi(pos);
+ } else
+ search_delay = wpas_p2p_search_delay(wpa_s);
+
+ return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
+ _dev_id, search_delay);
}
@@ -2335,14 +3831,19 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
enum p2p_wps_method wps_method;
int new_pin;
int ret;
- int persistent_group;
+ int persistent_group, persistent_id = -1;
int join;
int auth;
+ int automatic;
int go_intent = -1;
int freq = 0;
+ int pd;
+ int ht40, vht;
- /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] [persistent]
- * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
+ /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+ * [persistent|persistent=<network id>]
+ * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+ * [ht40] [vht] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -2353,8 +3854,26 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
pos++;
persistent_group = os_strstr(pos, " persistent") != NULL;
+ pos2 = os_strstr(pos, " persistent=");
+ if (pos2) {
+ struct wpa_ssid *ssid;
+ persistent_id = atoi(pos2 + 12);
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+ if (ssid == NULL || ssid->disabled != 2 ||
+ ssid->mode != WPAS_MODE_P2P_GO) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+ "SSID id=%d for persistent P2P group (GO)",
+ persistent_id);
+ return -1;
+ }
+ }
join = os_strstr(pos, " join") != NULL;
auth = os_strstr(pos, " auth") != NULL;
+ automatic = os_strstr(pos, " auto") != NULL;
+ pd = os_strstr(pos, " provdisc") != NULL;
+ vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+ vht;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -2386,11 +3905,16 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
}
+ if (!wps_pin_str_valid(pin)) {
+ os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
+ return 17;
+ }
}
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
- persistent_group, join, auth, go_intent,
- freq);
+ persistent_group, automatic, join,
+ auth, go_intent, freq, persistent_id, pd,
+ ht40, vht);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -2424,8 +3948,9 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
{
u8 addr[ETH_ALEN];
char *pos;
+ enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
- /* <addr> <config method> [join] */
+ /* <addr> <config method> [join|auto] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -2435,8 +3960,12 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
pos++;
- return wpas_p2p_prov_disc(wpa_s, addr, pos,
- os_strstr(pos, "join") != NULL);
+ if (os_strstr(pos, " join") != NULL)
+ use = WPAS_P2P_PD_FOR_JOIN;
+ else if (os_strstr(pos, " auto") != NULL)
+ use = WPAS_P2P_PD_AUTO;
+
+ return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
}
@@ -2484,8 +4013,11 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
if (*pos != ' ')
return -1;
pos++;
- ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, dst,
- version, pos);
+ ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
+ ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
+#endif /* CONFIG_WIFI_DISPLAY */
} else {
len = os_strlen(pos);
if (len & 1)
@@ -2499,9 +4031,11 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
return -1;
}
- ref = (unsigned long) wpas_p2p_sd_request(wpa_s, dst, tlvs);
+ ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
wpabuf_free(tlvs);
}
+ if (ref == 0)
+ return -1;
res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
if (res < 0 || (unsigned) res >= buflen)
return -1;
@@ -2517,7 +4051,7 @@ static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
if (sscanf(cmd, "%llx", &val) != 1)
return -1;
req = val;
- return wpas_p2p_sd_cancel_request(wpa_s, (void *) (unsigned long) req);
+ return wpas_p2p_sd_cancel_request(wpa_s, req);
}
@@ -2742,7 +4276,9 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
char *pos;
int id;
struct wpa_ssid *ssid;
- u8 peer[ETH_ALEN];
+ u8 *_peer = NULL, peer[ETH_ALEN];
+ int freq = 0, pref_freq = 0;
+ int ht40, vht;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -2750,6 +4286,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
pos += 6;
if (hwaddr_aton(pos, peer))
return -1;
+ _peer = peer;
}
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL || ssid->disabled != 2) {
@@ -2759,7 +4296,28 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
- return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
+ pos = os_strstr(cmd, " freq=");
+ if (pos) {
+ pos += 6;
+ freq = atoi(pos);
+ if (freq <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " pref=");
+ if (pos) {
+ pos += 6;
+ pref_freq = atoi(pos);
+ if (pref_freq <= 0)
+ return -1;
+ }
+
+ vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+ vht;
+
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
+ pref_freq);
}
@@ -2806,7 +4364,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,
- char *cmd, int freq)
+ char *cmd, int freq, int ht40,
+ int vht)
{
int id;
struct wpa_ssid *ssid;
@@ -2820,26 +4379,34 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, vht,
+ NULL, 0);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0;
+ int freq = 0, ht40, vht;
char *pos;
pos = os_strstr(cmd, "freq=");
if (pos)
freq = atoi(pos + 5);
+ vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
+ ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+ vht;
+
if (os_strncmp(cmd, "persistent=", 11) == 0)
- return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
+ return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
+ ht40, vht);
if (os_strcmp(cmd, "persistent") == 0 ||
os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq);
+ return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
if (os_strncmp(cmd, "freq=", 5) == 0)
- return wpas_p2p_group_add(wpa_s, 0, freq);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
+ if (ht40)
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
cmd);
@@ -2856,6 +4423,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
char *pos, *end;
char devtype[WPS_DEV_TYPE_BUFSIZE];
struct wpa_ssid *ssid;
+ size_t i;
if (!wpa_s->global->p2p)
return -1;
@@ -2909,6 +4477,18 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
return pos - buf;
pos += res;
+ for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+ {
+ const u8 *t;
+ t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+ res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+ wps_dev_type_bin2str(t, devtype,
+ sizeof(devtype)));
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+
ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
if (ssid) {
res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
@@ -2926,6 +4506,29 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
}
+static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
+ const char *param)
+{
+ unsigned int i;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
+ return -1;
+
+ for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
+ struct wpa_freq_range *freq;
+ freq = &wpa_s->global->p2p_disallow_freq.range[i];
+ wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
+ freq->min, freq->max);
+ }
+
+ wpas_p2p_update_channel_list(wpa_s);
+ return 0;
+}
+
+
static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
{
char *param;
@@ -3005,6 +4608,20 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
return 0;
}
+ if (os_strcmp(cmd, "conc_pref") == 0) {
+ if (os_strcmp(param, "sta") == 0)
+ wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
+ else if (os_strcmp(param, "p2p") == 0)
+ wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
+ else {
+ wpa_printf(MSG_INFO, "Invalid conc_pref value");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
+ "%s", param);
+ return 0;
+ }
+
if (os_strcmp(cmd, "force_long_sd") == 0) {
wpa_s->force_long_sd = atoi(param);
return 0;
@@ -3070,6 +4687,48 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
return 0;
}
+ if (os_strcmp(cmd, "disallow_freq") == 0)
+ return p2p_ctrl_disallow_freq(wpa_s, param);
+
+ if (os_strcmp(cmd, "disc_int") == 0) {
+ int min_disc_int, max_disc_int, max_disc_tu;
+ char *pos;
+
+ pos = param;
+
+ min_disc_int = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ max_disc_int = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ max_disc_tu = atoi(pos);
+
+ return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+ max_disc_int, max_disc_tu);
+ }
+
+ if (os_strcmp(cmd, "per_sta_psk") == 0) {
+ wpa_s->global->p2p_per_sta_psk = !!atoi(param);
+ return 0;
+ }
+
+#ifdef CONFIG_WPS_NFC
+ if (os_strcmp(cmd, "nfc_tag") == 0)
+ return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
+#endif /* CONFIG_WPS_NFC */
+
+ if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
+ wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -3077,6 +4736,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
}
+static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
+{
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ wpa_s->force_long_sd = 0;
+ if (wpa_s->global->p2p)
+ p2p_flush(wpa_s->global->p2p);
+}
+
+
static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *pos2;
@@ -3126,10 +4794,90 @@ static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
return wpas_p2p_ext_listen(wpa_s, period, interval);
}
+
+static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ u8 peer[ETH_ALEN];
+ int iface_addr = 0;
+
+ pos = cmd;
+ if (os_strncmp(pos, "iface=", 6) == 0) {
+ iface_addr = 1;
+ pos += 6;
+ }
+ if (hwaddr_aton(pos, peer))
+ return -1;
+
+ wpas_p2p_remove_client(wpa_s, peer, iface_addr);
+ return 0;
+}
+
#endif /* CONFIG_P2P */
+static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
+{
+ struct wpa_freq_range_list ranges;
+ int *freqs = NULL;
+ struct hostapd_hw_modes *mode;
+ u16 i;
+
+ if (wpa_s->hw.modes == NULL)
+ return NULL;
+
+ os_memset(&ranges, 0, sizeof(ranges));
+ if (freq_range_list_parse(&ranges, val) < 0)
+ return NULL;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ int j;
+
+ mode = &wpa_s->hw.modes[i];
+ for (j = 0; j < mode->num_channels; j++) {
+ unsigned int freq;
+
+ if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ freq = mode->channels[j].freq;
+ if (!freq_range_list_includes(&ranges, freq))
+ continue;
+
+ int_array_add_unique(&freqs, freq);
+ }
+ }
+
+ os_free(ranges.range);
+ return freqs;
+}
+
+
#ifdef CONFIG_INTERWORKING
+
+static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
+{
+ int auto_sel = 0;
+ int *freqs = NULL;
+
+ if (param) {
+ char *pos;
+
+ auto_sel = os_strstr(param, "auto") != NULL;
+
+ pos = os_strstr(param, "freq=");
+ if (pos) {
+ freqs = freq_range_to_channel_list(wpa_s, pos + 5);
+ if (freqs == NULL)
+ return -1;
+ }
+
+ }
+
+ return interworking_select(wpa_s, auto_sel, freqs);
+}
+
+
static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
{
u8 bssid[ETH_ALEN];
@@ -3179,9 +4927,251 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
return anqp_send_req(wpa_s, dst_addr, id, num_id);
}
+
+
+static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ struct wpabuf *advproto, *query = NULL;
+ int used, ret = -1;
+ char *pos, *end;
+ size_t len;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+
+ /* Advertisement Protocol ID */
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+ if (len == 0)
+ return -1;
+ advproto = wpabuf_alloc(len);
+ if (advproto == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
+ goto fail;
+
+ if (end) {
+ /* Optional Query Request */
+ pos = end + 1;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len) {
+ if (len & 0x01)
+ goto fail;
+ len /= 2;
+ if (len == 0)
+ goto fail;
+ query = wpabuf_alloc(len);
+ if (query == NULL)
+ goto fail;
+ if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
+ goto fail;
+ }
+ }
+
+ ret = gas_send_request(wpa_s, dst_addr, advproto, query);
+
+fail:
+ wpabuf_free(advproto);
+ wpabuf_free(query);
+
+ return ret;
+}
+
+
+static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ int dialog_token;
+ int used;
+ char *pos;
+ size_t resp_len, start, requested_len;
+ struct wpabuf *resp;
+ int ret;
+
+ used = hwaddr_aton2(cmd, addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+ dialog_token = atoi(pos);
+
+ if (wpa_s->last_gas_resp &&
+ os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
+ dialog_token == wpa_s->last_gas_dialog_token)
+ resp = wpa_s->last_gas_resp;
+ else if (wpa_s->prev_gas_resp &&
+ os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
+ dialog_token == wpa_s->prev_gas_dialog_token)
+ resp = wpa_s->prev_gas_resp;
+ else
+ return -1;
+
+ resp_len = wpabuf_len(resp);
+ start = 0;
+ requested_len = resp_len;
+
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ start = atoi(pos);
+ if (start > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ requested_len = atoi(pos);
+ if (start + requested_len > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ }
+
+ if (requested_len * 2 + 1 > buflen)
+ return os_snprintf(buf, buflen, "FAIL-Too long response");
+
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
+ requested_len);
+
+ if (start + requested_len == resp_len) {
+ /*
+ * Free memory by dropping the response after it has been
+ * fetched.
+ */
+ if (resp == wpa_s->prev_gas_resp) {
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = NULL;
+ } else {
+ wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = NULL;
+ }
+ }
+
+ return ret;
+}
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+
+static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *pos;
+ u32 subtypes = 0;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+ pos = dst + used;
+ for (;;) {
+ int num = atoi(pos);
+ if (num <= 0 || num > 31)
+ return -1;
+ subtypes |= BIT(num);
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ if (subtypes == 0)
+ return -1;
+
+ return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+}
+
+
+static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const char *realm)
+{
+ u8 *buf;
+ size_t rlen, len;
+ int ret;
+
+ rlen = os_strlen(realm);
+ len = 3 + rlen;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+ buf[0] = 1; /* NAI Home Realm Count */
+ buf[1] = 0; /* Formatted in accordance with RFC 4282 */
+ buf[2] = rlen;
+ os_memcpy(buf + 3, realm, rlen);
+
+ ret = hs20_anqp_send_req(wpa_s, addr,
+ BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+ buf, len);
+
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+ char *dst)
+{
+ struct wpa_cred *cred = wpa_s->conf->cred;
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (dst[used] == ' ')
+ used++;
+ if (os_strncmp(dst + used, "realm=", 6) == 0)
+ return hs20_nai_home_realm_list(wpa_s, dst_addr,
+ dst + used + 6);
+
+ len = os_strlen(dst + used);
+
+ if (len == 0 && cred && cred->realm)
+ return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
+
+ if (len % 1)
+ return -1;
+ len /= 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(dst + used, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ ret = hs20_anqp_send_req(wpa_s, dst_addr,
+ BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+ buf, len);
+ os_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_HS20 */
+
+
static int wpa_supplicant_ctrl_iface_sta_autoconnect(
struct wpa_supplicant *wpa_s, char *cmd)
{
@@ -3190,44 +5180,600 @@ static int wpa_supplicant_ctrl_iface_sta_autoconnect(
}
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ enum wpa_states state = wpa_s->wpa_state;
+ char *new_params = NULL;
+
+ if (os_strlen(cmd) > 0) {
+ new_params = os_strdup(cmd);
+ if (new_params == NULL)
+ return -1;
+ }
+
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = new_params;
+
+ if (wpa_s->conf->autoscan == NULL)
+ autoscan_deinit(wpa_s);
+ else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ autoscan_init(wpa_s, 1);
+ else if (state == WPA_SCANNING)
+ wpa_supplicant_reinit_autoscan(wpa_s);
+
+ return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
+#ifdef CONFIG_WNM
+
+static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int enter;
+ int intval = 0;
+ char *pos;
+ int ret;
+ struct wpabuf *tfs_req = NULL;
+
+ if (os_strncmp(cmd, "enter", 5) == 0)
+ enter = 1;
+ else if (os_strncmp(cmd, "exit", 4) == 0)
+ enter = 0;
+ else
+ return -1;
+
+ pos = os_strstr(cmd, " interval=");
+ if (pos)
+ intval = atoi(pos + 10);
+
+ pos = os_strstr(cmd, " tfs_req=");
+ if (pos) {
+ char *end;
+ size_t len;
+ pos += 9;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ tfs_req = wpabuf_alloc(len);
+ if (tfs_req == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
+ wpabuf_free(tfs_req);
+ return -1;
+ }
+ }
+
+ ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
+ WNM_SLEEP_MODE_EXIT, intval,
+ tfs_req);
+ wpabuf_free(tfs_req);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int query_reason;
+
+ query_reason = atoi(cmd);
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
+ query_reason);
+
+ return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+}
+
+#endif /* CONFIG_WNM */
+
+
+/* Get string representation of channel width */
+static const char * channel_width_name(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ return "20 MHz (no HT)";
+ case CHAN_WIDTH_20:
+ return "20 MHz";
+ case CHAN_WIDTH_40:
+ return "40 MHz";
+ case CHAN_WIDTH_80:
+ return "80 MHz";
+ case CHAN_WIDTH_80P80:
+ return "80+80 MHz";
+ case CHAN_WIDTH_160:
+ return "160 MHz";
+ default:
+ return "unknown";
+ }
+}
+
+
static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
struct wpa_signal_info si;
int ret;
+ char *pos, *end;
ret = wpa_drv_signal_poll(wpa_s, &si);
if (ret)
return -1;
- ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+ pos = buf;
+ end = buf + buflen;
+
+ ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
"NOISE=%d\nFREQUENCY=%u\n",
si.current_signal, si.current_txrate / 1000,
si.current_noise, si.frequency);
- if (ret < 0 || (unsigned int) ret > buflen)
+ if (ret < 0 || ret > end - pos)
+ return -1;
+ pos += ret;
+
+ if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+ ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+ channel_width_name(si.chanwidth));
+ if (ret < 0 || ret > end - pos)
+ return -1;
+ pos += ret;
+ }
+
+ if (si.center_frq1 > 0 && si.center_frq2 > 0) {
+ ret = os_snprintf(pos, end - pos,
+ "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
+ si.center_frq1, si.center_frq2);
+ if (ret < 0 || ret > end - pos)
+ return -1;
+ pos += ret;
+ }
+
+ if (si.avg_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_RSSI=%d\n", si.avg_signal);
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
+ size_t buflen)
+{
+ struct hostap_sta_driver_data sta;
+ int ret;
+
+ ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
+ if (ret)
+ return -1;
+
+ ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
+ sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
+ if (ret < 0 || (size_t) ret > buflen)
+ return -1;
+ return ret;
+}
+
+
+#ifdef ANDROID
+static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+
+ ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ if (ret == 0) {
+ if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ if (p2p) {
+ char country[3];
+ country[0] = cmd[8];
+ country[1] = cmd[9];
+ country[2] = 0x04;
+ p2p_set_country(p2p, country);
+ }
+ }
+ ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ }
+ return ret;
+}
+#endif /* ANDROID */
+
+
+static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+
+#ifdef CONFIG_P2P
+ wpas_p2p_stop_find(wpa_s);
+ p2p_ctrl_flush(wpa_s);
+ wpas_p2p_group_remove(wpa_s, "*");
+ wpas_p2p_service_flush(wpa_s);
+ wpa_s->global->p2p_disabled = 0;
+ wpa_s->global->p2p_per_sta_psk = 0;
+ wpa_s->conf->num_sec_device_types = 0;
+ wpa_s->p2p_disable_ip_addr_req = 0;
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS_TESTING
+ wps_version_number = 0x20;
+ wps_testing_dummy_cred = 0;
+ wps_corrupt_pkhash = 0;
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_WPS
+ wpa_s->wps_fragment_size = 0;
+ wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+
+#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);
+ wpa_tdls_enable(wpa_s->wpa, 1);
+#endif /* CONFIG_TDLS */
+
+ eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+ wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+
+ wpa_s->no_keep_alive = 0;
+
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = NULL;
+ wpa_s->disallow_aps_bssid_count = 0;
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = NULL;
+ wpa_s->disallow_aps_ssid_count = 0;
+
+ wpa_s->set_sta_uapsd = 0;
+ wpa_s->sta_uapsd = 0;
+
+ wpa_drv_radio_disable(wpa_s, 0);
+
+ wpa_bss_flush(wpa_s);
+ wpa_blacklist_clear(wpa_s);
+ wpa_s->extra_blacklist_count = 0;
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
+ wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+ wpa_config_flush_blobs(wpa_s->conf);
+ wpa_s->conf->auto_interworking = 0;
+ wpa_s->conf->okc = 0;
+ wpa_s->conf->pmf = 0;
+
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
+ wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
+ eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+
+ radio_remove_unstarted_work(wpa_s, NULL);
+}
+
+
+static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct wpa_radio_work *work;
+ char *pos, *end;
+ struct os_reltime now, diff;
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ int ret;
+
+ os_reltime_sub(&now, &work->time, &diff);
+ ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
+ work->type, work->wpa_s->ifname, work->freq,
+ work->started, diff.sec, diff.usec);
+ if (ret < 0 || ret >= end - pos)
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_radio_work *work = eloop_ctx;
+ struct wpa_external_work *ework = work->ctx;
+
+ wpa_dbg(work->wpa_s, MSG_DEBUG,
+ "Timing out external radio work %u (%s)",
+ ework->id, work->type);
+ wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
+ os_free(ework);
+ radio_work_done(work);
+}
+
+
+static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_external_work *ework = work->ctx;
+
+ if (deinit) {
+ os_free(ework);
+ return;
+ }
+
+ wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
+ ework->id, ework->type);
+ wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
+ if (!ework->timeout)
+ ework->timeout = 10;
+ eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
+ work, NULL);
+}
+
+
+static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ struct wpa_external_work *ework;
+ char *pos, *pos2;
+ size_t type_len;
+ int ret;
+ unsigned int freq = 0;
+
+ /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
+
+ ework = os_zalloc(sizeof(*ework));
+ if (ework == NULL)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos) {
+ type_len = pos - cmd;
+ pos++;
+
+ pos2 = os_strstr(pos, "freq=");
+ if (pos2)
+ freq = atoi(pos2 + 5);
+
+ pos2 = os_strstr(pos, "timeout=");
+ if (pos2)
+ ework->timeout = atoi(pos2 + 8);
+ } else {
+ type_len = os_strlen(cmd);
+ }
+ if (4 + type_len >= sizeof(ework->type))
+ type_len = sizeof(ework->type) - 4 - 1;
+ os_strlcpy(ework->type, "ext:", sizeof(ework->type));
+ os_memcpy(ework->type + 4, cmd, type_len);
+ ework->type[4 + type_len] = '\0';
+
+ wpa_s->ext_work_id++;
+ if (wpa_s->ext_work_id == 0)
+ wpa_s->ext_work_id++;
+ ework->id = wpa_s->ext_work_id;
+
+ if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
+ ework) < 0) {
+ os_free(ework);
+ return -1;
+ }
+
+ ret = os_snprintf(buf, buflen, "%u", ework->id);
+ if (ret < 0 || (size_t) ret >= buflen)
return -1;
return ret;
}
+static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct wpa_radio_work *work;
+ unsigned int id = atoi(cmd);
+
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ struct wpa_external_work *ework;
+
+ if (os_strncmp(work->type, "ext:", 4) != 0)
+ continue;
+ ework = work->ctx;
+ if (id && ework->id != id)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Completed external radio work %u (%s)",
+ ework->id, ework->type);
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
+ os_free(ework);
+ radio_work_done(work);
+ return 3; /* "OK\n" */
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ if (os_strcmp(cmd, "show") == 0)
+ return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
+ if (os_strncmp(cmd, "add ", 4) == 0)
+ return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
+ if (os_strncmp(cmd, "done ", 5) == 0)
+ return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
+ return -1;
+}
+
+
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio_work *work, *tmp;
+
+ if (!wpa_s || !wpa_s->radio)
+ return;
+
+ dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
+ struct wpa_radio_work, list) {
+ struct wpa_external_work *ework;
+
+ if (os_strncmp(work->type, "ext:", 4) != 0)
+ continue;
+ ework = work->ctx;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Flushing %sexternal radio work %u (%s)",
+ work->started ? " started" : "", ework->id,
+ ework->type);
+ if (work->started)
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+ work, NULL);
+ os_free(ework);
+ radio_work_done(work);
+ }
+}
+
+
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
+static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val)
+{
+ int *freqs = NULL;
+
+ freqs = freq_range_to_channel_list(wpa_s, val);
+ if (freqs == NULL)
+ return -1;
+
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = freqs;
+
+ return 0;
+}
+
+
+static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
+ char *reply, int reply_size, int *reply_len)
+{
+ char *pos;
+
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ *reply_len = -1;
+ return;
+ }
+
+ wpa_s->manual_scan_passive = 0;
+ wpa_s->manual_scan_use_id = 0;
+ wpa_s->manual_scan_only_new = 0;
+
+ if (params) {
+ if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
+ wpa_s->scan_res_handler = scan_only_handler;
+
+ pos = os_strstr(params, "freq=");
+ if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) {
+ *reply_len = -1;
+ return;
+ }
+
+ pos = os_strstr(params, "passive=");
+ if (pos)
+ wpa_s->manual_scan_passive = !!atoi(pos + 8);
+
+ pos = os_strstr(params, "use_id=");
+ if (pos)
+ wpa_s->manual_scan_use_id = atoi(pos + 7);
+
+ pos = os_strstr(params, "only_new=1");
+ if (pos)
+ wpa_s->manual_scan_only_new = 1;
+ } else {
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = NULL;
+ if (wpa_s->scan_res_handler == scan_only_handler)
+ wpa_s->scan_res_handler = NULL;
+ }
+
+ if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+ ((wpa_s->wpa_state <= WPA_SCANNING) ||
+ (wpa_s->wpa_state == WPA_COMPLETED))) {
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->manual_scan_use_id) {
+ wpa_s->manual_scan_id++;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+ wpa_s->manual_scan_id);
+ *reply_len = os_snprintf(reply, reply_size, "%u\n",
+ wpa_s->manual_scan_id);
+ }
+ } else if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->manual_scan_use_id) {
+ wpa_s->manual_scan_id++;
+ *reply_len = os_snprintf(reply, reply_size, "%u\n",
+ wpa_s->manual_scan_id);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+ wpa_s->manual_scan_id);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
+ *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+ }
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
char *reply;
const int reply_size = 4096;
- int ctrl_rsp = 0;
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ if (wpa_debug_show_keys)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Control interface command '%s'", buf);
+ else
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Control interface command '%s [REMOVED]'",
+ os_strncmp(buf, WPA_CTRL_RSP,
+ os_strlen(WPA_CTRL_RSP)) == 0 ?
+ WPA_CTRL_RSP : "SET_NETWORK");
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+ os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
+ os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
(const u8 *) buf, os_strlen(buf));
} else {
int level = MSG_DEBUG;
if (os_strcmp(buf, "PING") == 0)
level = MSG_EXCESSIVE;
- wpa_hexdump_ascii(level, "RX ctrl_iface",
- (const u8 *) buf, os_strlen(buf));
+ wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
}
reply = os_malloc(reply_size);
@@ -3242,6 +5788,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
+ } else if (os_strcmp(buf, "IFNAME") == 0) {
+ reply_len = os_strlen(wpa_s->ifname);
+ os_memcpy(reply, wpa_s->ifname, reply_len);
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
@@ -3277,19 +5826,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
- else {
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
+ else
+ wpas_request_connection(wpa_s);
} else if (os_strcmp(buf, "RECONNECT") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
- else if (wpa_s->disconnected) {
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
+ else if (wpa_s->disconnected)
+ wpas_request_connection(wpa_s);
#ifdef IEEE8021X_EAPOL
} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
@@ -3330,11 +5873,39 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
if (wpas_wps_cancel(wpa_s))
reply_len = -1;
-#ifdef CONFIG_WPS_OOB
- } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
- if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strcmp(buf, "WPS_NFC") == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
+ } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
+ wpa_s, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
+ buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_req(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_sel(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+ reply_len = wpas_ctrl_nfc_rx_handover_req(
+ wpa_s, buf + 20, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+ if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
+ reply_len = -1;
+#endif /* CONFIG_WPS_NFC */
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
reply_len = -1;
@@ -3379,6 +5950,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+ wpa_s, buf + 24, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS_ER */
#endif /* CONFIG_WPS */
#ifdef CONFIG_IBSS_RSN
@@ -3408,7 +5984,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_p2p_group_remove(wpa_s, buf + 17))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
- if (wpas_p2p_group_add(wpa_s, 0, 0))
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -3453,10 +6029,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
- os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
- wpa_s->force_long_sd = 0;
- if (wpa_s->global->p2p)
- p2p_flush(wpa_s->global->p2p);
+ p2p_ctrl_flush(wpa_s);
} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
reply_len = -1;
@@ -3475,16 +6048,29 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
+ if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
+ reply_len = -1;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
+ if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
+ reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
+ reply, reply_size);
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
if (interworking_fetch_anqp(wpa_s) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
interworking_stop_fetch_anqp(wpa_s);
- } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
- if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
- NULL) < 0)
+ } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
+ if (ctrl_interworking_select(wpa_s, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
+ if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
@@ -3492,14 +6078,34 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
if (get_anqp(wpa_s, buf + 9) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
+ if (gas_request(wpa_s, buf + 12) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
+ reply_len = gas_response_get(wpa_s, buf + 17, reply,
+ reply_size);
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
+ if (get_hs20_anqp(wpa_s, buf + 14) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
+ if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
+ reply_len = -1;
+#endif /* CONFIG_HS20 */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
{
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
reply_len = -1;
- else
- ctrl_rsp = 1;
+ else {
+ /*
+ * Notify response from timeout to allow the control
+ * interface response to be sent first.
+ */
+ eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+ wpa_s, NULL);
+ }
} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
if (wpa_supplicant_reload_configuration(wpa_s))
reply_len = -1;
@@ -3523,24 +6129,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
#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);
} else if (os_strcmp(buf, "SCAN") == 0) {
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
- reply_len = -1;
- else {
- if (!wpa_s->scanning &&
- ((wpa_s->wpa_state <= WPA_SCANNING) ||
- (wpa_s->wpa_state == WPA_COMPLETED))) {
- wpa_s->scan_req = 2;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else {
- wpa_printf(MSG_DEBUG, "Ongoing scan action - "
- "reject new request");
- reply_len = os_snprintf(reply, reply_size,
- "FAIL-BUSY\n");
- }
- }
+ wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
+ } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
+ wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
@@ -3565,6 +6161,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get_network(
wpa_s, buf + 12, reply, reply_size);
+ } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_list_creds(
+ wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "ADD_CRED") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_add_cred(
+ wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
+ if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
+ reply_len = -1;
#ifndef CONFIG_NO_CONFIG_WRITE
} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
@@ -3597,6 +6205,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
reply_size);
+ } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+ if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+ if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+ if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+ reply_len = -1;
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -3617,6 +6234,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
buf + 17))
reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
+ if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
+ reply_len = -1;
#ifdef CONFIG_TDLS
} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
@@ -3631,6 +6251,35 @@ 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, "PKTCNT_POLL", 11) == 0) {
+ reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
+ reply_size);
+#ifdef CONFIG_AUTOSCAN
+ } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
+ reply_len = -1;
+#endif /* CONFIG_AUTOSCAN */
+#ifdef ANDROID
+ } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
+ reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
+ reply_size);
+#endif /* ANDROID */
+ } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+ pmksa_cache_clear_current(wpa_s->wpa);
+ eapol_sm_request_reauth(wpa_s->eapol);
+#ifdef CONFIG_WNM
+ } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
+ if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
+ if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+ reply_len = -1;
+#endif /* CONFIG_WNM */
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ wpa_supplicant_ctrl_iface_flush(wpa_s);
+ } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
+ reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -3641,9 +6290,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = 5;
}
- if (ctrl_rsp)
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
*resp_len = reply_len;
return reply;
}
@@ -3736,7 +6382,7 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
wpa_s = wpa_supplicant_get_iface(global, cmd);
if (wpa_s == NULL)
return -1;
- return wpa_supplicant_remove_iface(global, wpa_s);
+ return wpa_supplicant_remove_iface(global, wpa_s, 0);
}
@@ -3821,6 +6467,231 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
}
+static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
+ const char *ifname,
+ char *cmd, size_t *resp_len)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (os_strcmp(ifname, wpa_s->ifname) == 0)
+ break;
+ }
+
+ if (wpa_s == NULL) {
+ char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
+ if (resp)
+ *resp_len = os_strlen(resp);
+ else
+ *resp_len = 1;
+ return resp;
+ }
+
+ return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
+}
+
+
+static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_P2P
+ static const char * cmd[] = {
+ "LIST_NETWORKS",
+ "SAVE_CONFIG",
+ "P2P_FIND",
+ "P2P_STOP_FIND",
+ "P2P_LISTEN",
+ "P2P_GROUP_ADD",
+ "P2P_GET_PASSPHRASE",
+ "P2P_SERVICE_UPDATE",
+ "P2P_SERVICE_FLUSH",
+ "P2P_FLUSH",
+ "P2P_CANCEL",
+ "P2P_PRESENCE_REQ",
+ "P2P_EXT_LISTEN",
+ NULL
+ };
+ static const char * prefix[] = {
+#ifdef ANDROID
+ "DRIVER ",
+#endif /* ANDROID */
+ "GET_NETWORK ",
+ "REMOVE_NETWORK ",
+ "SET ",
+ "P2P_FIND ",
+ "P2P_CONNECT ",
+ "P2P_LISTEN ",
+ "P2P_GROUP_REMOVE ",
+ "P2P_GROUP_ADD ",
+ "P2P_PROV_DISC ",
+ "P2P_SERV_DISC_REQ ",
+ "P2P_SERV_DISC_CANCEL_REQ ",
+ "P2P_SERV_DISC_RESP ",
+ "P2P_SERV_DISC_EXTERNAL ",
+ "P2P_SERVICE_ADD ",
+ "P2P_SERVICE_DEL ",
+ "P2P_REJECT ",
+ "P2P_INVITE ",
+ "P2P_PEER ",
+ "P2P_SET ",
+ "P2P_UNAUTHORIZE ",
+ "P2P_PRESENCE_REQ ",
+ "P2P_EXT_LISTEN ",
+ "P2P_REMOVE_CLIENT ",
+ NULL
+ };
+ int found = 0;
+ int i;
+
+ if (global->p2p_init_wpa_s == NULL)
+ return NULL;
+
+ for (i = 0; !found && cmd[i]; i++) {
+ if (os_strcmp(buf, cmd[i]) == 0)
+ found = 1;
+ }
+
+ for (i = 0; !found && prefix[i]; i++) {
+ if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
+ found = 1;
+ }
+
+ if (found)
+ return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+ buf, resp_len);
+#endif /* CONFIG_P2P */
+ return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_WIFI_DISPLAY
+ if (global->p2p_init_wpa_s == NULL)
+ return NULL;
+ if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
+ os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
+ return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+ buf, resp_len);
+#endif /* CONFIG_WIFI_DISPLAY */
+ return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
+ char *ret;
+
+ ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
+ if (ret)
+ return ret;
+
+ ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+
+static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
+{
+ char *value;
+
+ value = os_strchr(cmd, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(global, !!atoi(value));
+ return 0;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ return -1;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
+{
+ int ret = 0;
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (!wpa_s->conf->update_config) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
+ continue;
+ }
+
+ if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
+ ret = 1;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
+ }
+ }
+
+ return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int wpas_global_ctrl_iface_status(struct wpa_global *global,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ int ret;
+ struct wpa_supplicant *wpa_s;
+
+ pos = buf;
+ end = buf + buflen;
+
+#ifdef CONFIG_P2P
+ if (global->p2p && !global->p2p_disabled) {
+ ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+ "\n"
+ "p2p_state=%s\n",
+ MAC2STR(global->p2p_dev_addr),
+ p2p_get_state_txt(global->p2p));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ } else if (global->p2p) {
+ ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+ ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
+ !!global->wifi_display);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ret = os_snprintf(pos, end - pos, "ifname=%s\n"
+ "address=" MACSTR "\n",
+ wpa_s->ifname, MAC2STR(wpa_s->own_addr));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
char *buf, size_t *resp_len)
{
@@ -3829,6 +6700,20 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
int reply_len;
int level = MSG_DEBUG;
+ if (os_strncmp(buf, "IFNAME=", 7) == 0) {
+ char *pos = os_strchr(buf + 7, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ return wpas_global_ctrl_iface_ifname(global,
+ buf + 7, pos,
+ resp_len);
+ }
+ }
+
+ reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
+ if (reply)
+ return reply;
+
if (os_strcmp(buf, "PING") == 0)
level = MSG_EXCESSIVE;
wpa_hexdump_ascii(level, "RX global ctrl_iface",
@@ -3864,6 +6749,17 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
wpas_notify_suspend(global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(global);
+ } else if (os_strncmp(buf, "SET ", 4) == 0) {
+ if (wpas_global_ctrl_iface_set(global, buf + 4))
+ reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+ } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+ if (wpas_global_ctrl_iface_save_config(global))
+ reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ } else if (os_strcmp(buf, "STATUS") == 0) {
+ reply_len = wpas_global_ctrl_iface_status(global, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index 051d99a..b0dec53 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -2,14 +2,8 @@
* WPA Supplicant / UNIX domain socket -based control interface
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_H
@@ -119,6 +113,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
void wpa_supplicant_global_ctrl_iface_deinit(
struct ctrl_iface_global_priv *priv);
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s);
+
#else /* CONFIG_CTRL_IFACE */
static inline struct ctrl_iface_priv *
@@ -154,6 +150,10 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
}
+static inline void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c
index 5f7e24d..dc02db2 100644
--- a/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -2,14 +2,8 @@
* WPA Supplicant / Windows Named Pipe -based control interface
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -429,7 +423,7 @@ static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
}
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 110ca4f..8c09ba1 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -2,14 +2,8 @@
* WPA Supplicant / UDP socket -based control interface
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -86,14 +80,14 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
while (dst) {
if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
from->sin_port == dst->addr.sin_port) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+ "%s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
if (prev == NULL)
priv->ctrl_dst = dst->next;
else
prev->next = dst->next;
os_free(dst);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
- "%s:%d", inet_ntoa(from->sin_addr),
- ntohs(from->sin_port));
return 0;
}
prev = dst;
@@ -169,6 +163,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -180,6 +176,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -257,7 +255,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
}
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -272,6 +270,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -291,13 +290,25 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port--;
+ if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -320,13 +331,13 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
eloop_unregister_read_sock(priv->sock);
if (priv->ctrl_dst) {
/*
- * Wait a second before closing the control socket if
+ * Wait before closing the control socket if
* there are any attached monitors in order to allow
* them to receive any pending messages.
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
"monitors to receive messages");
- os_sleep(1, 0);
+ os_sleep(0, 100000);
}
close(priv->sock);
priv->sock = -1;
@@ -448,6 +459,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -459,6 +472,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -508,6 +523,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
struct ctrl_iface_global_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_GLOBAL_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -529,13 +545,26 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port++;
+ if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
+ WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 306a222..d44313c 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -17,6 +11,8 @@
#include <sys/stat.h>
#include <grp.h>
#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
#ifdef ANDROID
#include <cutils/sockets.h>
#endif /* ANDROID */
@@ -54,16 +50,32 @@ struct ctrl_iface_priv {
};
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+struct ctrl_iface_global_priv {
+ struct wpa_global *global;
+ int sock;
+ struct dl_list ctrl_dst;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
+ struct dl_list *ctrl_dst,
int level, const char *buf,
- size_t len);
+ size_t len,
+ struct ctrl_iface_priv *priv,
+ struct ctrl_iface_global_priv *gp);
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv);
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv);
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
struct sockaddr_un *from,
socklen_t fromlen)
{
struct wpa_ctrl_dst *dst;
+ char addr_txt[200];
dst = os_zalloc(sizeof(*dst));
if (dst == NULL)
@@ -71,31 +83,35 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
- dl_list_add(&priv->ctrl_dst, &dst->list);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
- (u8 *) from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
+ 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 monitor attached %s", addr_txt);
return 0;
}
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
struct sockaddr_un *from,
socklen_t fromlen)
{
struct wpa_ctrl_dst *dst;
- dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
+ 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);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
return 0;
}
}
@@ -117,11 +133,13 @@ static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
os_memcmp(from->sun_path, dst->addr.sun_path,
fromlen - offsetof(struct sockaddr_un, sun_path))
== 0) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
- "level", (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
+ 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;
}
}
@@ -139,27 +157,30 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char *reply = NULL;
+ char *reply = NULL, *reply_buf = NULL;
size_t reply_len = 0;
int new_attached = 0;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
if (os_strcmp(buf, "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(buf, "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;
@@ -170,21 +191,49 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
else
reply_len = 2;
} else {
- reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
- &reply_len);
+ reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+ &reply_len);
+ reply = reply_buf;
+ }
+
+ if (!reply && reply_len == 1) {
+ reply = "FAIL\n";
+ reply_len = 5;
+ } else if (!reply && reply_len == 2) {
+ reply = "OK\n";
+ reply_len = 3;
}
if (reply) {
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
- fromlen);
- os_free(reply);
- } 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);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ int _errno = errno;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "ctrl_iface sendto failed: %d - %s",
+ _errno, strerror(_errno));
+ if (_errno == ENOBUFS || _errno == EAGAIN) {
+ /*
+ * The socket send buffer could be full. This
+ * may happen if client programs are not
+ * receiving their pending messages. Close and
+ * reopen the socket as a workaround to avoid
+ * getting stuck being unable to send any new
+ * responses.
+ */
+ sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+ if (sock < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
+ }
+ }
+ if (new_attached) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
+ new_attached = 0;
+ wpa_supplicant_ctrl_iface_detach(
+ &priv->ctrl_dst, &from, fromlen);
+ }
+ }
}
+ os_free(reply_buf);
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -244,20 +293,38 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
- if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+ if (wpa_s == NULL)
return;
- wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+ if (global != 2 && wpa_s->global->ctrl_iface) {
+ struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+ if (!dl_list_empty(&priv->ctrl_dst)) {
+ wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL :
+ wpa_s->ifname,
+ priv->sock,
+ &priv->ctrl_dst,
+ level, txt, len, NULL,
+ priv);
+ }
+ }
+
+ if (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);
}
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
- struct ctrl_iface_priv *priv;
struct sockaddr_un addr;
char *fname = NULL;
gid_t gid = 0;
@@ -265,16 +332,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
char *buf, *dir = NULL, *gid_str = NULL;
struct group *grp;
char *endp;
-
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
- dl_list_init(&priv->ctrl_dst);
- priv->wpa_s = wpa_s;
- priv->sock = -1;
-
- if (wpa_s->conf->ctrl_interface == NULL)
- return priv;
+ int flags;
buf = os_strdup(wpa_s->conf->ctrl_interface);
if (buf == NULL)
@@ -303,11 +361,28 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
+ dir, strerror(errno));
goto fail;
}
}
+#ifdef ANDROID
+ /*
+ * wpa_supplicant is started from /init.*.rc on Android and that seems
+ * to be using umask 0077 which would leave the control interface
+ * directory without group access. This breaks things since Wi-Fi
+ * framework assumes that this directory can be accessed by other
+ * applications in the wifi group. Fix this by adding group access even
+ * if umask value would prevent this.
+ */
+ if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+#endif /* ANDROID */
+
if (gid_str) {
grp = getgrnam(gid_str);
if (grp) {
@@ -331,7 +406,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (gid_set && chown(dir, -1, gid) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ dir, (int) gid, strerror(errno));
goto fail;
}
@@ -351,7 +427,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -373,15 +449,15 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -398,12 +474,14 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (gid_set && chown(fname, -1, gid) < 0) {
- perror("chown[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ fname, (int) gid, strerror(errno));
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
+ fname, strerror(errno));
goto fail;
}
os_free(fname);
@@ -411,23 +489,81 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
#ifdef ANDROID
havesock:
#endif /* ANDROID */
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+ strerror(errno));
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
os_free(buf);
- return priv;
+ return 0;
fail:
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
close(priv->sock);
- os_free(priv);
+ priv->sock = -1;
+ }
if (fname) {
unlink(fname);
os_free(fname);
}
os_free(buf);
- return NULL;
+ return -1;
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ dl_list_init(&priv->ctrl_dst);
+ priv->wpa_s = wpa_s;
+ priv->sock = -1;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
+{
+ int res;
+
+ if (priv->sock <= 0)
+ return -1;
+
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ priv->sock = -1;
+ res = wpas_ctrl_iface_open_sock(wpa_s, priv);
+ if (res < 0)
+ return -1;
+ return priv->sock;
}
@@ -441,13 +577,13 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
eloop_unregister_read_sock(priv->sock);
if (!dl_list_empty(&priv->ctrl_dst)) {
/*
- * Wait a second before closing the control socket if
+ * Wait before closing the control socket if
* there are any attached monitors in order to allow
* them to receive any pending messages.
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
"monitors to receive messages");
- os_sleep(1, 0);
+ os_sleep(0, 100000);
}
close(priv->sock);
priv->sock = -1;
@@ -457,6 +593,8 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
os_free(fname);
}
+ if (priv->wpa_s->conf->ctrl_interface == NULL)
+ goto free_dst;
buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
if (buf == NULL)
goto free_dst;
@@ -476,7 +614,9 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ dir, strerror(errno));
}
}
os_free(buf);
@@ -492,63 +632,109 @@ free_dst:
/**
* wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @ifname: Interface name for global control socket or %NULL
+ * @sock: Local socket fd
+ * @ctrl_dst: List of attached listeners
* @level: Priority level of the message
* @buf: Message data
* @len: Message length
*
* Send a packet to all monitor programs attached to the control interface.
*/
-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 dl_list *ctrl_dst,
int level, const char *buf,
- size_t len)
+ size_t len,
+ struct ctrl_iface_priv *priv,
+ struct ctrl_iface_global_priv *gp)
{
struct wpa_ctrl_dst *dst, *next;
char levelstr[10];
int idx, res;
struct msghdr msg;
- struct iovec io[2];
+ struct iovec io[5];
- if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
+ if (sock < 0 || dl_list_empty(ctrl_dst))
return;
res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
if (res < 0 || (size_t) res >= sizeof(levelstr))
return;
- io[0].iov_base = levelstr;
- io[0].iov_len = os_strlen(levelstr);
- io[1].iov_base = (char *) buf;
- io[1].iov_len = len;
+ idx = 0;
+ if (ifname) {
+ io[idx].iov_base = "IFNAME=";
+ io[idx].iov_len = 7;
+ idx++;
+ io[idx].iov_base = (char *) ifname;
+ io[idx].iov_len = os_strlen(ifname);
+ idx++;
+ io[idx].iov_base = " ";
+ io[idx].iov_len = 1;
+ idx++;
+ }
+ io[idx].iov_base = levelstr;
+ io[idx].iov_len = os_strlen(levelstr);
+ idx++;
+ io[idx].iov_base = (char *) buf;
+ io[idx].iov_len = len;
+ idx++;
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
- msg.msg_iovlen = 2;
+ msg.msg_iovlen = idx;
- idx = 0;
- dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst,
- list) {
- if (level >= dst->debug_level) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
- (u8 *) dst->addr.sun_path, dst->addrlen -
- offsetof(struct sockaddr_un, sun_path));
- msg.msg_name = (void *) &dst->addr;
- msg.msg_namelen = dst->addrlen;
- if (sendmsg(priv->sock, &msg, 0) < 0) {
- int _errno = errno;
- wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
- "%d - %s",
- idx, errno, strerror(errno));
- dst->errors++;
- if (dst->errors > 1000 ||
- (_errno != ENOBUFS && dst->errors > 10) ||
- _errno == ENOENT) {
- wpa_supplicant_ctrl_iface_detach(
- priv, &dst->addr,
- dst->addrlen);
- }
- } else
- dst->errors = 0;
+ dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
+ int _errno;
+ char addr_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;
+ if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor sent successfully to %s",
+ addr_txt);
+ dst->errors = 0;
+ continue;
+ }
+
+ _errno = errno;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
+ addr_txt, errno, strerror(errno));
+ 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);
+ wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
+ dst->addrlen);
+ }
+
+ if (_errno == ENOBUFS || _errno == EAGAIN) {
+ /*
+ * The socket send buffer could be full. This may happen
+ * if client programs are not receiving their pending
+ * messages. Close and reopen the socket as a workaround
+ * to avoid getting stuck being unable to send any new
+ * responses.
+ */
+ if (priv)
+ sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+ else if (gp)
+ sock = wpas_ctrl_iface_global_reinit(
+ wpa_s->global, gp);
+ else
+ break;
+ if (sock < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to reinitialize ctrl_iface socket");
+ break;
+ }
}
- idx++;
}
}
@@ -568,27 +754,40 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
continue;
}
buf[res] = '\0';
if (os_strcmp(buf, "ATTACH") == 0) {
/* handle ATTACH signal of first monitor interface */
- if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
- fromlen)) {
- sendto(priv->sock, "OK\n", 3, 0,
- (struct sockaddr *) &from, fromlen);
+ if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+ &from, fromlen)) {
+ if (sendto(priv->sock, "OK\n", 3, 0,
+ (struct sockaddr *) &from, fromlen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
/* OK to continue */
return;
} else {
- sendto(priv->sock, "FAIL\n", 5, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "FAIL\n", 5, 0,
+ (struct sockaddr *) &from, fromlen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
} else {
/* return FAIL for all other signals */
- sendto(priv->sock, "FAIL\n", 5, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "FAIL\n", 5, 0,
+ (struct sockaddr *) &from, fromlen) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
}
}
@@ -596,72 +795,105 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
/* Global ctrl_iface */
-struct ctrl_iface_global_priv {
- struct wpa_global *global;
- int sock;
-};
-
-
static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct wpa_global *global = eloop_ctx;
- char buf[256];
+ struct ctrl_iface_global_priv *priv = sock_ctx;
+ char buf[4096];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char *reply;
+ char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
- reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
- &reply_len);
+ if (os_strcmp(buf, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+ fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
+ fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else {
+ reply_buf = wpa_supplicant_global_ctrl_iface_process(
+ global, buf, &reply_len);
+ reply = reply_buf;
+ }
+
+ if (!reply && reply_len == 1) {
+ reply = "FAIL\n";
+ reply_len = 5;
+ } else if (!reply && reply_len == 2) {
+ reply = "OK\n";
+ reply_len = 3;
+ }
if (reply) {
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
- fromlen);
- os_free(reply);
- } else if (reply_len) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
+ os_free(reply_buf);
}
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv)
{
- struct ctrl_iface_global_priv *priv;
struct sockaddr_un addr;
+ const char *ctrl = global->params.ctrl_interface;
+ int flags;
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
- priv->global = global;
- priv->sock = -1;
-
- if (global->params.ctrl_interface == NULL)
- return priv;
+ wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
#ifdef ANDROID
- priv->sock = android_get_control_socket(global->params.ctrl_interface);
- if (priv->sock >= 0)
+ if (os_strncmp(ctrl, "@android:", 9) == 0) {
+ priv->sock = android_get_control_socket(ctrl + 9);
+ if (priv->sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open Android control "
+ "socket '%s'", ctrl + 9);
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
+ ctrl + 9);
goto havesock;
-#endif /* ANDROID */
+ }
- wpa_printf(MSG_DEBUG, "Global control interface '%s'",
- global->params.ctrl_interface);
+ if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
+ /*
+ * Backwards compatibility - try to open an Android control
+ * socket and if that fails, assume this was a UNIX domain
+ * socket instead.
+ */
+ priv->sock = android_get_control_socket(ctrl);
+ if (priv->sock >= 0) {
+ wpa_printf(MSG_DEBUG,
+ "Using Android control socket '%s'",
+ ctrl);
+ goto havesock;
+ }
+ }
+#endif /* ANDROID */
priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -670,65 +902,187 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
addr.sun_len = sizeof(addr);
#endif /* __FreeBSD__ */
addr.sun_family = AF_UNIX;
- os_strlcpy(addr.sun_path, global->params.ctrl_interface,
- sizeof(addr.sun_path));
+
+ if (os_strncmp(ctrl, "@abstract:", 10) == 0) {
+ addr.sun_path[0] = '\0';
+ os_strlcpy(addr.sun_path + 1, ctrl + 10,
+ sizeof(addr.sun_path) - 1);
+ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
+ "bind(PF_UNIX;%s) failed: %s",
+ ctrl, strerror(errno));
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
+ ctrl + 10);
+ goto havesock;
+ }
+
+ os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
+ ctrl, strerror(errno));
if (connect(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
" allow connections - assuming it was left"
"over from forced program termination");
- if (unlink(global->params.ctrl_interface) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- global->params.ctrl_interface);
+ if (unlink(ctrl) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ ctrl, strerror(errno));
goto fail;
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
+ ctrl, strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
"ctrl_iface socket '%s'",
- global->params.ctrl_interface);
+ ctrl);
} else {
wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
"be in use - cannot override it");
wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
"not used anymore",
- global->params.ctrl_interface);
+ ctrl);
goto fail;
}
}
-#ifdef ANDROID
+ wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl);
+
+ if (global->params.ctrl_interface_group) {
+ char *gid_str = global->params.ctrl_interface_group;
+ gid_t gid = 0;
+ struct group *grp;
+ char *endp;
+
+ grp = getgrnam(gid_str);
+ if (grp) {
+ gid = grp->gr_gid;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ (int) gid, gid_str);
+ } else {
+ /* Group name not found - try to parse this as gid */
+ gid = strtol(gid_str, &endp, 10);
+ if (*gid_str == '\0' || *endp != '\0') {
+ wpa_printf(MSG_ERROR, "CTRL: Invalid group "
+ "'%s'", gid_str);
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ (int) gid);
+ }
+ if (chown(ctrl, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR,
+ "chown[global_ctrl_interface=%s,gid=%d]: %s",
+ ctrl, (int) gid, strerror(errno));
+ goto fail;
+ }
+
+ if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR,
+ "chmod[global_ctrl_interface=%s]: %s",
+ ctrl, strerror(errno));
+ goto fail;
+ }
+ } else {
+ chmod(ctrl, S_IRWXU);
+ }
+
havesock:
-#endif /* ANDROID */
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+ strerror(errno));
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
- global, NULL);
+ global, priv);
- return priv;
+ return 0;
fail:
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
close(priv->sock);
- os_free(priv);
- return NULL;
+ priv->sock = -1;
+ }
+ return -1;
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ dl_list_init(&priv->ctrl_dst);
+ priv->global = global;
+ priv->sock = -1;
+
+ if (global->params.ctrl_interface == NULL)
+ return priv;
+
+ if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ return priv;
+}
+
+
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv)
+{
+ int res;
+
+ if (priv->sock <= 0)
+ return -1;
+
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ priv->sock = -1;
+ res = wpas_global_ctrl_iface_open_sock(global, priv);
+ if (res < 0)
+ return -1;
+ return priv->sock;
}
void
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
+ struct wpa_ctrl_dst *dst, *prev;
+
if (priv->sock >= 0) {
eloop_unregister_read_sock(priv->sock);
close(priv->sock);
}
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)
+ os_free(dst);
os_free(priv);
}
diff --git a/wpa_supplicant/dbus/Makefile b/wpa_supplicant/dbus/Makefile
index d64c65c..f355ebe 100644
--- a/wpa_supplicant/dbus/Makefile
+++ b/wpa_supplicant/dbus/Makefile
@@ -1,7 +1,7 @@
all: libwpadbus.a
clean:
- rm -f *~ *.o *.d
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov
rm -f libwpadbus.a
install:
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5850636..6caf740 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -23,6 +17,7 @@
#include "dbus_common_i.h"
#include "dbus_new.h"
#include "dbus_old.h"
+#include "../wpa_supplicant_i.h"
#ifndef SIGPOLL
@@ -263,6 +258,22 @@ static int integrate_with_eloop(struct wpas_dbus_priv *priv)
}
+static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+ DBusMessage *message, void *data)
+{
+ struct wpas_dbus_priv *priv = data;
+
+ if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
+ "Disconnected")) {
+ wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+ wpa_supplicant_terminate_proc(priv->global);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
{
DBusError error;
@@ -271,7 +282,10 @@ static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
/* Get a reference to the system bus */
dbus_error_init(&error);
priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
- if (!priv->con) {
+ if (priv->con) {
+ dbus_connection_add_filter(priv->con, disconnect_filter, priv,
+ NULL);
+ } else {
wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
"bus: %s - %s", error.name, error.message);
ret = -1;
@@ -310,6 +324,9 @@ static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
NULL, NULL, NULL);
dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
NULL, NULL, NULL);
+ dbus_connection_remove_filter(priv->con, disconnect_filter,
+ priv);
+
dbus_connection_unref(priv->con);
}
diff --git a/wpa_supplicant/dbus/dbus_common.h b/wpa_supplicant/dbus/dbus_common.h
index 50da09b..aea7db7 100644
--- a/wpa_supplicant/dbus/dbus_common.h
+++ b/wpa_supplicant/dbus/dbus_common.h
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DBUS_COMMON_H
diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/wpa_supplicant/dbus/dbus_common_i.h
index 9dab1ee..a551ccd 100644
--- a/wpa_supplicant/dbus/dbus_common_i.h
+++ b/wpa_supplicant/dbus/dbus_common_i.h
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DBUS_COMMON_I_H
@@ -25,6 +19,10 @@ struct wpas_dbus_priv {
struct wpa_global *global;
u32 next_objid;
int dbus_new_initialized;
+
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+ int dbus_noc_refcnt;
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
};
#endif /* DBUS_COMMON_I_H */
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 5f9e64a..61a9430 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -739,12 +733,12 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
{
dbus_uint32_t count = 0;
dbus_bool_t success = FALSE;
- char *buffer, *nbuffer;;
+ char *buffer, *nbuffer;
entry->bytearray_value = NULL;
entry->array_type = DBUS_TYPE_BYTE;
- buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
if (!buffer)
return FALSE;
@@ -754,8 +748,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
char byte;
if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
- (count + BYTE_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + BYTE_ARRAY_CHUNK_SIZE,
+ BYTE_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -801,7 +796,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
entry->strarray_value = NULL;
entry->array_type = DBUS_TYPE_STRING;
- buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
if (buffer == NULL)
return FALSE;
@@ -812,8 +807,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
char *str;
if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
- (count + STR_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + STR_ARRAY_CHUNK_SIZE,
+ STR_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -877,8 +873,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
buflen += BIN_ARRAY_CHUNK_SIZE;
- newbuf = os_realloc(entry->binarray_value,
- buflen * BIN_ARRAY_ITEM_SIZE);
+ newbuf = os_realloc_array(entry->binarray_value,
+ buflen, BIN_ARRAY_ITEM_SIZE);
if (!newbuf)
goto cleanup;
entry->binarray_value = newbuf;
@@ -1104,5 +1100,5 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
break;
}
- memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+ os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 2f6eb45..9666349 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DBUS_DICT_HELPERS_H
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 6725f78..f40d421 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -27,11 +21,103 @@
#include "dbus_dict_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
-#include "dbus_common.h"
#include "dbus_common_i.h"
#include "dbus_new_handlers_p2p.h"
#include "p2p/p2p.h"
+#ifdef CONFIG_AP /* until needed by something else */
+
+/*
+ * NameOwnerChanged handling
+ *
+ * Some services we provide allow an application to register for
+ * a signal that it needs. While it can also unregister, we must
+ * be prepared for the case where the application simply crashes
+ * and thus doesn't clean up properly. The way to handle this in
+ * DBus is to register for the NameOwnerChanged signal which will
+ * signal an owner change to NULL if the peer closes the socket
+ * for whatever reason.
+ *
+ * Handle this signal via a filter function whenever necessary.
+ * The code below also handles refcounting in case in the future
+ * there will be multiple instances of this subscription scheme.
+ */
+static const char wpas_dbus_noc_filter_str[] =
+ "interface=org.freedesktop.DBus,member=NameOwnerChanged";
+
+
+static DBusHandlerResult noc_filter(DBusConnection *conn,
+ DBusMessage *message, void *data)
+{
+ struct wpas_dbus_priv *priv = data;
+
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged")) {
+ const char *name;
+ const char *prev_owner;
+ const char *new_owner;
+ DBusError derr;
+ struct wpa_supplicant *wpa_s;
+
+ dbus_error_init(&derr);
+
+ if (!dbus_message_get_args(message, &derr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &prev_owner,
+ DBUS_TYPE_STRING, &new_owner,
+ DBUS_TYPE_INVALID)) {
+ /* Ignore this error */
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ {
+ if (wpa_s->preq_notify_peer != NULL &&
+ os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
+ (new_owner == NULL || os_strlen(new_owner) == 0)) {
+ /* probe request owner disconnected */
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ }
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
+{
+ priv->dbus_noc_refcnt++;
+ if (priv->dbus_noc_refcnt > 1)
+ return;
+
+ if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
+ wpa_printf(MSG_ERROR, "dbus: failed to add filter");
+ return;
+ }
+
+ dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+}
+
+
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
+{
+ priv->dbus_noc_refcnt--;
+ if (priv->dbus_noc_refcnt > 0)
+ return;
+
+ dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+ dbus_connection_remove_filter(priv->con, noc_filter, priv);
+}
+
+#endif /* CONFIG_AP */
+
/**
* wpas_dbus_signal_interface - Send a interface related event signal
@@ -748,6 +834,111 @@ nomem:
dbus_message_unref(msg);
}
+
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status, const char *parameter)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "EAP");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
+ ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+ &parameter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_sta - Send a station related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ * @sig_name: signal name - StaAuthorized or StaDeauthorized
+ *
+ * Notify listeners about event related with station
+ */
+static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta, const char *sig_name)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
+ char *dev_mac;
+
+ os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
+ dev_mac = sta_mac;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+ if (msg == NULL)
+ return;
+
+ if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac,
+ DBUS_TYPE_INVALID))
+ dbus_connection_send(iface->con, msg, NULL);
+ else
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+
+ wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
+ sta_mac, sig_name);
+}
+
+
+/**
+ * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a new station has been authorized
+ */
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
+}
+
+
+/**
+ * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a station has been deauthorized
+ */
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
+}
+
+
#ifdef CONFIG_P2P
/**
@@ -954,7 +1145,7 @@ static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
return -1;
- memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+ os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
group_name[2] = '\0';
os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -1171,7 +1362,7 @@ void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- wpa_printf(MSG_INFO, "%s\n", __func__);
+ wpa_printf(MSG_DEBUG, "%s", __func__);
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
@@ -1601,10 +1792,12 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
enum wpas_dbus_prop property)
{
char *prop;
+ dbus_bool_t flush;
if (wpa_s->dbus_new_path == NULL)
return; /* Skip signal since D-Bus setup is not yet ready */
+ flush = FALSE;
switch (property) {
case WPAS_DBUS_PROP_AP_SCAN:
prop = "ApScan";
@@ -1627,6 +1820,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
prop = "CurrentAuthMode";
break;
+ case WPAS_DBUS_PROP_DISCONNECT_REASON:
+ prop = "DisconnectReason";
+ flush = TRUE;
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -1636,6 +1833,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
wpa_dbus_mark_property_changed(wpa_s->global->dbus,
wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+ if (flush) {
+ wpa_dbus_flush_object_changed_properties(
+ wpa_s->global->dbus->con, wpa_s->dbus_new_path);
+ }
}
@@ -1677,6 +1878,9 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
case WPAS_DBUS_BSS_PROP_RSN:
prop = "RSN";
break;
+ case WPAS_DBUS_BSS_PROP_WPS:
+ prop = "WPS";
+ break;
case WPAS_DBUS_BSS_PROP_IES:
prop = "IEs";
break;
@@ -2027,11 +2231,11 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
struct wpas_dbus_priv *ctrl_iface;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
int ret;
+#ifdef CONFIG_P2P
struct wpa_ssid *ssid;
ssid = wpa_config_get_network(wpa_s->conf, nid);
-#ifdef CONFIG_P2P
/* If it is a persistent group unregister it as such */
if (ssid && network_is_persistent_group(ssid))
return wpas_dbus_unregister_persistent_group(wpa_s, nid);
@@ -2096,6 +2300,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
wpas_dbus_getter_bss_rsn,
NULL
},
+ { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+ wpas_dbus_getter_bss_wps,
+ NULL
+ },
{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_ies,
NULL
@@ -2248,6 +2456,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+ {
+ END_ARGS
+ }
+ },
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
{
@@ -2277,6 +2491,7 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
{
@@ -2300,6 +2515,16 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+ { "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler)
+ &wpas_dbus_handler_set_pkcs11_engine_and_module_path,
+ {
+ { "pkcs11_engine_path", "s", ARG_IN },
+ { "pkcs11_module_path", "s", ARG_IN },
+ END_ARGS
+ }
+ },
#ifdef CONFIG_WPS
{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
(WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
@@ -2485,6 +2710,72 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+#ifdef CONFIG_AP
+ { "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
+ {
+ END_ARGS
+ }
+ },
+ { "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AP */
+ { "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff,
+ {
+ END_ARGS
+ }
+ },
+ { "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon,
+ {
+ END_ARGS
+ }
+ },
+#ifdef CONFIG_AUTOSCAN
+ { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+ {
+ { "arg", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_TDLS
+ { "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_status,
+ {
+ { "peer_address", "s", ARG_IN },
+ { "status", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_TDLS */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -2557,6 +2848,18 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
wpas_dbus_getter_fast_reauth,
wpas_dbus_setter_fast_reauth
},
+ { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_scan_interval,
+ wpas_dbus_setter_scan_interval
+ },
+ { "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_pkcs11_engine_path,
+ NULL
+ },
+ { "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_pkcs11_module_path,
+ NULL
+ },
#ifdef CONFIG_WPS
{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
wpas_dbus_getter_process_credentials,
@@ -2589,6 +2892,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
NULL
},
#endif /* CONFIG_P2P */
+ { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_disconnect_reason,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -2807,12 +3114,39 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
}
},
#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+ { "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AP */
{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
{
{ "certification", "a{sv}", ARG_OUT },
END_ARGS
}
},
+ { "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "status", "s", ARG_OUT },
+ { "parameter", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "name", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "name", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
{ NULL, NULL, { END_ARGS } }
};
@@ -2880,6 +3214,15 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
wpa_s->dbus_new_path);
+
+#ifdef CONFIG_AP
+ if (wpa_s->preq_notify_peer) {
+ wpas_dbus_unsubscribe_noc(ctrl_iface);
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ }
+#endif /* CONFIG_AP */
+
if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
wpa_s->dbus_new_path))
return -1;
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 93ce722..61c480a 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_DBUS_NEW_H
@@ -34,6 +28,7 @@ enum wpas_dbus_prop {
WPAS_DBUS_PROP_CURRENT_NETWORK,
WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
WPAS_DBUS_PROP_BSSS,
+ WPAS_DBUS_PROP_DISCONNECT_REASON,
};
enum wpas_dbus_bss_prop {
@@ -44,6 +39,7 @@ enum wpas_dbus_bss_prop {
WPAS_DBUS_BSS_PROP_RATES,
WPAS_DBUS_BSS_PROP_WPA,
WPAS_DBUS_BSS_PROP_RSN,
+ WPAS_DBUS_BSS_PROP_WPS,
WPAS_DBUS_BSS_PROP_IES,
};
@@ -115,6 +111,17 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \
+ WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse"
+#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \
+ WPAS_DBUS_NEW_INTERFACE ".NoSubscription"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
+ WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
+
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -210,6 +217,15 @@ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
const char *cert_hash,
const struct wpabuf *cert);
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status, const char *parameter);
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta);
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta);
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
@@ -467,6 +483,32 @@ static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
{
}
+static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst,
+ const u8 *bssid,
+ const u8 *ie, size_t ie_len,
+ u32 ssi_signal)
+{
+}
+
+static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status,
+ const char *parameter)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 1669968..5380b43 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -25,18 +19,14 @@
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
#include "../notify.h"
-#include "../wpas_glue.h"
#include "../bss.h"
#include "../scan.h"
-#include "../ctrl_iface.h"
+#include "../autoscan.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
+#include "dbus_common_i.h"
static const char *debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
@@ -129,7 +119,7 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
static const char *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", NULL
+ "bssid", "scan_freq", "freq_list", NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -254,7 +244,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
- (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+ (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
wpa_config_update_psk(ssid);
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
@@ -548,25 +538,25 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!strcmp(entry.key, "Driver") &&
+ if (!os_strcmp(entry.key, "Driver") &&
(entry.type == DBUS_TYPE_STRING)) {
driver = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver == NULL)
goto error;
- } else if (!strcmp(entry.key, "Ifname") &&
+ } else if (!os_strcmp(entry.key, "Ifname") &&
(entry.type == DBUS_TYPE_STRING)) {
ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (ifname == NULL)
goto error;
- } else if (!strcmp(entry.key, "ConfigFile") &&
+ } else if (!os_strcmp(entry.key, "ConfigFile") &&
(entry.type == DBUS_TYPE_STRING)) {
confname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (confname == NULL)
goto error;
- } else if (!strcmp(entry.key, "BridgeIfname") &&
+ } else if (!os_strcmp(entry.key, "BridgeIfname") &&
(entry.type == DBUS_TYPE_STRING)) {
bridge_ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
@@ -614,6 +604,7 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
out:
os_free(driver);
os_free(ifname);
+ os_free(confname);
os_free(bridge_ifname);
return reply;
@@ -647,7 +638,7 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
wpa_s = get_iface_by_dbus_path(global, path);
if (wpa_s == NULL)
reply = wpas_dbus_error_iface_unknown(message);
- else if (wpa_supplicant_remove_iface(global, wpa_s)) {
+ else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_error_unknown_error(
message, "wpa_supplicant couldn't remove this "
"interface.");
@@ -875,7 +866,7 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
num++;
- paths = os_zalloc(num * sizeof(char*));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -1201,8 +1192,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
#define FREQS_ALLOC_CHUNK 32
if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
- nfreqs = os_realloc(freqs, sizeof(int) *
- (freqs_num + FREQS_ALLOC_CHUNK));
+ nfreqs = os_realloc_array(
+ freqs, freqs_num + FREQS_ALLOC_CHUNK,
+ sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
@@ -1222,8 +1214,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
dbus_message_iter_next(&array_iter);
}
- nfreqs = os_realloc(freqs,
- sizeof(int) * (freqs_num + 1));
+ nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
@@ -1241,6 +1232,23 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
}
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+ DBusMessageIter *var,
+ dbus_bool_t *allow,
+ DBusMessage **reply)
+{
+ if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+ wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+ "Type must be a boolean");
+ *reply = wpas_dbus_error_invalid_args(
+ message, "Wrong Type value type. Boolean required");
+ return -1;
+ }
+ dbus_message_iter_get_basic(var, allow);
+ return 0;
+}
+
+
/**
* wpas_dbus_handler_scan - Request a wireless scan on an interface
* @message: Pointer to incoming dbus message
@@ -1259,6 +1267,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
char *key = NULL, *type = NULL;
struct wpa_driver_scan_params params;
size_t i;
+ dbus_bool_t allow_roam = 1;
os_memset(&params, 0, sizeof(params));
@@ -1289,6 +1298,12 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
if (wpas_dbus_get_scan_channels(message, &variant_iter,
&params, &reply) < 0)
goto out;
+ } else if (os_strcmp(key, "AllowRoam") == 0) {
+ if (wpas_dbus_get_scan_allow_roam(message,
+ &variant_iter,
+ &allow_roam,
+ &reply) < 0)
+ goto out;
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Unknown argument %s", key);
@@ -1317,7 +1332,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
} else if (params.freqs && params.freqs[0]) {
wpa_supplicant_trigger_scan(wpa_s, &params);
} else {
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
} else if (!os_strcmp(type, "active")) {
@@ -1325,6 +1340,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
/* Add wildcard ssid */
params.num_ssids++;
}
+#ifdef CONFIG_AUTOSCAN
+ autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
wpa_supplicant_trigger_scan(wpa_s, &params);
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
@@ -1334,6 +1352,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
goto out;
}
+ if (!allow_roam)
+ wpa_s->scan_res_handler = scan_only_handler;
+
out:
for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
os_free((u8 *) params.ssids[i].ssid);
@@ -1444,6 +1465,28 @@ err:
/**
+ * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Reassociate" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->current_ssid != NULL) {
+ wpas_request_connection(wpa_s);
+ return NULL;
+ }
+
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+ "This interface is not connected");
+}
+
+
+/**
* wpas_dbus_handler_remove_network - Remove a configured network
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
@@ -1459,6 +1502,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
char *iface = NULL, *net_id = NULL;
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
@@ -1466,13 +1510,15 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
@@ -1483,6 +1529,8 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
goto out;
}
+ was_disabled = ssid->disabled;
+
wpas_notify_network_removed(wpa_s, ssid);
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
@@ -1498,6 +1546,13 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
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);
+ }
+
out:
os_free(iface);
@@ -1521,7 +1576,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
}
if (ssid == wpa_s->current_ssid)
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
}
@@ -1536,6 +1592,9 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
DBusMessage * wpas_dbus_handler_remove_all_networks(
DBusMessage *message, struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
/* NB: could check for failure and return an error */
wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
return NULL;
@@ -1565,13 +1624,15 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
@@ -1620,13 +1681,15 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, net_id);
goto out;
}
@@ -1656,6 +1719,8 @@ out:
}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
/**
* wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
* @message: Pointer to incoming dbus message
@@ -1820,6 +1885,9 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
/*
* wpas_dbus_handler_flush_bss - Flush the BSS cache
* @message: Pointer to incoming dbus message
@@ -1845,6 +1913,307 @@ DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
}
+#ifdef CONFIG_AUTOSCAN
+/**
+ * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "AutoScan" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ enum wpa_states state = wpa_s->wpa_state;
+ char *arg;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
+ DBUS_TYPE_INVALID);
+
+ if (arg != NULL && os_strlen(arg) > 0) {
+ char *tmp;
+ tmp = os_strdup(arg);
+ if (tmp == NULL) {
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_NO_MEMORY,
+ NULL);
+ } else {
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = tmp;
+ if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ autoscan_init(wpa_s, 1);
+ else if (state == WPA_SCANNING)
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ }
+ } else if (arg != NULL && os_strlen(arg) == 0) {
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = NULL;
+ autoscan_deinit(wpa_s);
+ } else
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_INVALID_ARGS,
+ NULL);
+
+ return reply;
+}
+#endif /* CONFIG_AUTOSCAN */
+
+
+/*
+ * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogoff" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogin" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ return NULL;
+}
+
+
+#ifdef CONFIG_TDLS
+
+static DBusMessage * get_peer_hwaddr_helper(DBusMessage *message,
+ const char *func_name,
+ u8 *peer_address)
+{
+ const char *peer_string;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &peer_string,
+ DBUS_TYPE_INVALID))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (hwaddr_aton(peer_string, peer_address)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
+ func_name, peer_string);
+ return wpas_dbus_error_invalid_args(
+ message, "Invalid hardware address format");
+ }
+
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_discover - Discover TDLS peer
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSDiscover" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 peer[ETH_ALEN];
+ DBusMessage *error_reply;
+ int ret;
+
+ error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+ if (error_reply)
+ return error_reply;
+
+ wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+ if (ret) {
+ return wpas_dbus_error_unknown_error(
+ message, "error performing TDLS discovery");
+ }
+
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_setup - Setup TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSSetup" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 peer[ETH_ALEN];
+ DBusMessage *error_reply;
+ int ret;
+
+ error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+ if (error_reply)
+ return error_reply;
+
+ wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
+
+ wpa_tdls_remove(wpa_s->wpa, peer);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+ if (ret) {
+ return wpas_dbus_error_unknown_error(
+ message, "error performing TDLS setup");
+ }
+
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_status - Return TDLS session status
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A string representing the state of the link to this TDLS peer
+ *
+ * Handler function for "TDLSStatus" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 peer[ETH_ALEN];
+ DBusMessage *reply;
+ const char *tdls_status;
+
+ reply = get_peer_hwaddr_helper(message, __func__, peer);
+ if (reply)
+ return reply;
+
+ wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
+
+ tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_STRING,
+ &tdls_status, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSTeardown" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 peer[ETH_ALEN];
+ DBusMessage *error_reply;
+ int ret;
+
+ error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+ if (error_reply)
+ return error_reply;
+
+ wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_teardown_link(
+ wpa_s->wpa, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ if (ret) {
+ return wpas_dbus_error_unknown_error(
+ message, "error performing TDLS teardown");
+ }
+
+ return NULL;
+}
+
+#endif /* CONFIG_TDLS */
+
+
+/**
+ * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing an error on failure or NULL on success
+ *
+ * Sets the PKCS #11 engine and module path.
+ */
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter;
+ char *value = NULL;
+ char *pkcs11_engine_path = NULL;
+ char *pkcs11_module_path = NULL;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &value);
+ if (value == NULL) {
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid pkcs11_engine_path argument");
+ }
+ /* Empty path defaults to NULL */
+ if (os_strlen(value))
+ pkcs11_engine_path = value;
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &value);
+ if (value == NULL) {
+ os_free(pkcs11_engine_path);
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid pkcs11_module_path argument");
+ }
+ /* Empty path defaults to NULL */
+ if (os_strlen(value))
+ pkcs11_module_path = value;
+
+ if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
+ pkcs11_module_path))
+ return dbus_message_new_error(
+ message, DBUS_ERROR_FAILED,
+ "Reinit of the EAPOL state machine with the new PKCS "
+ "#11 engine and module path failed.");
+
+ wpa_dbus_mark_property_changed(
+ wpa_s->global->dbus, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
+ wpa_dbus_mark_property_changed(
+ wpa_s->global->dbus, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
+
+ return NULL;
+}
+
+
/**
* wpas_dbus_getter_capabilities - Return interface capabilities
* @iter: Pointer to incoming dbus message iter
@@ -1878,7 +2247,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = {"ccmp", "tkip", "none"};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
@@ -1887,12 +2256,30 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
&iter_array))
goto nomem;
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256"))
+ goto nomem;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "ccmp"))
goto nomem;
}
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip"))
@@ -1919,7 +2306,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
@@ -1928,12 +2315,30 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
&iter_array))
goto nomem;
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256"))
+ goto nomem;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "ccmp"))
goto nomem;
}
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip"))
@@ -1970,7 +2375,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "KeyMgmt", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
@@ -2050,7 +2455,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = { "rsn", "wpa" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Protocol", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
@@ -2085,7 +2490,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = { "open", "shared", "leap" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "AuthAlg", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
@@ -2121,7 +2526,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
/***** Scan */
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
- sizeof(scans) / sizeof(char *)))
+ ARRAY_SIZE(scans)))
goto nomem;
/***** Modes */
@@ -2338,6 +2743,27 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
/**
+ * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
+ * @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 "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)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t reason = wpa_s->disconnect_reason;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &reason, 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
@@ -2501,6 +2927,56 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
/**
+ * wpas_dbus_getter_scan_interval - Get scan interval
+ * @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 function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t scan_interval = wpa_s->scan_interval;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &scan_interval, error);
+}
+
+
+/**
+ * wpas_dbus_setter_scan_interval - Control scan interval
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t scan_interval;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
+ &scan_interval))
+ return FALSE;
+
+ if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "scan_interval must be >= 0");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_getter_ifname - Get interface name
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -2656,9 +3132,7 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *bridge_ifname;
-
- bridge_ifname = wpa_s->bridge_ifname ? wpa_s->bridge_ifname : "";
+ const char *bridge_ifname = wpa_s->bridge_ifname;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&bridge_ifname, error);
}
@@ -2682,7 +3156,7 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
unsigned int i = 0;
dbus_bool_t success = FALSE;
- paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+ paths = os_calloc(wpa_s->num_bss, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -2745,7 +3219,7 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
if (!network_is_persistent_group(ssid))
num++;
- paths = os_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -2780,6 +3254,76 @@ out:
/**
+ * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 engine path
+ *
+ * Getter for "PKCS11EnginePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *pkcs11_engine_path;
+
+ if (wpa_s->conf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
+ "error occurred getting the PKCS #11 engine path.");
+ dbus_set_error_const(
+ error, DBUS_ERROR_FAILED,
+ "An error occured getting the PKCS #11 engine path.");
+ return FALSE;
+ }
+
+ if (wpa_s->conf->pkcs11_engine_path == NULL)
+ pkcs11_engine_path = "";
+ else
+ pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+ &pkcs11_engine_path, error);
+}
+
+
+/**
+ * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 module path
+ *
+ * Getter for "PKCS11ModulePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *pkcs11_module_path;
+
+ if (wpa_s->conf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
+ "error occurred getting the PKCS #11 module path.");
+ dbus_set_error_const(
+ error, DBUS_ERROR_FAILED,
+ "An error occured getting the PKCS #11 module path.");
+ return FALSE;
+ }
+
+ if (wpa_s->conf->pkcs11_module_path == NULL)
+ pkcs11_module_path = "";
+ else
+ pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+ &pkcs11_module_path, error);
+}
+
+
+/**
* wpas_dbus_getter_blobs - Get all blobs defined for this interface
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3077,7 +3621,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
- const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
+ const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
const char *key_mgmt[7]; /* max 7 key managements may be supported */
int n;
@@ -3120,9 +3664,18 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
case WPA_CIPHER_CCMP:
group = "ccmp";
break;
+ case WPA_CIPHER_GCMP:
+ group = "gcmp";
+ break;
case WPA_CIPHER_WEP104:
group = "wep104";
break;
+ case WPA_CIPHER_CCMP_256:
+ group = "ccmp-256";
+ break;
+ case WPA_CIPHER_GCMP_256:
+ group = "gcmp-256";
+ break;
default:
group = "";
break;
@@ -3137,6 +3690,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
pairwise[n++] = "tkip";
if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
pairwise[n++] = "ccmp";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
+ pairwise[n++] = "gcmp";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
+ pairwise[n++] = "ccmp-256";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
+ pairwise[n++] = "gcmp-256";
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
pairwise, n))
@@ -3244,6 +3803,63 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
/**
+ * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
+ * @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 "WPS" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+ void *user_data)
+{
+ struct bss_handler_args *args = user_data;
+ struct wpa_bss *res;
+#ifdef CONFIG_WPS
+ struct wpabuf *wps_ie;
+#endif /* CONFIG_WPS */
+ DBusMessageIter iter_dict, variant_iter;
+ const char *type = "";
+
+ res = get_bss_helper(args, error, __func__);
+ if (!res)
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter))
+ goto nomem;
+
+ if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ goto nomem;
+
+#ifdef CONFIG_WPS
+ wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+ if (wps_ie) {
+ if (wps_is_selected_pbc_registrar(wps_ie))
+ type = "pbc";
+ else if (wps_is_selected_pin_registrar(wps_ie))
+ type = "pin";
+ }
+#endif /* CONFIG_WPS */
+
+ if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
+ goto nomem;
+
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+ goto nomem;
+ if (!dbus_message_iter_close_container(iter, &variant_iter))
+ goto nomem;
+
+ return TRUE;
+
+nomem:
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+}
+
+
+/**
* wpas_dbus_getter_bss_ies - Return all IEs of a BSS
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3403,3 +4019,139 @@ dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
dbus_message_iter_recurse(iter, &variant_iter);
return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
}
+
+
+#ifdef CONFIG_AP
+
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+ char *name;
+
+ if (wpa_s->preq_notify_peer != NULL) {
+ if (os_strcmp(dbus_message_get_sender(message),
+ wpa_s->preq_notify_peer) == 0)
+ return NULL;
+
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
+ "Another application is already subscribed");
+ }
+
+ name = os_strdup(dbus_message_get_sender(message));
+ if (!name)
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ "out of memory");
+
+ wpa_s->preq_notify_peer = name;
+
+ /* Subscribe to clean up if application closes socket */
+ wpas_dbus_subscribe_noc(priv);
+
+ /*
+ * Double-check it's still alive to make sure that we didn't
+ * miss the NameOwnerChanged signal, e.g. while strdup'ing.
+ */
+ if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
+ /*
+ * Application no longer exists, clean up.
+ * The return value is irrelevant now.
+ *
+ * Need to check if the NameOwnerChanged handling
+ * already cleaned up because we have processed
+ * DBus messages while checking if the name still
+ * has an owner.
+ */
+ if (!wpa_s->preq_notify_peer)
+ return NULL;
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ }
+
+ return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+ if (!wpa_s->preq_notify_peer)
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
+ "Not subscribed");
+
+ if (os_strcmp(wpa_s->preq_notify_peer,
+ dbus_message_get_sender(message)))
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
+ "Can't unsubscribe others");
+
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ return NULL;
+}
+
+
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (priv == NULL)
+ return;
+
+ if (wpa_s->preq_notify_peer == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "ProbeRequest");
+ if (msg == NULL)
+ return;
+
+ dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto fail;
+ if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+ (const char *) addr,
+ ETH_ALEN))
+ goto fail;
+ if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+ (const char *) dst,
+ ETH_ALEN))
+ goto fail;
+ if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+ (const char *) bssid,
+ ETH_ALEN))
+ goto fail;
+ if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+ (const char *) ie,
+ ie_len))
+ goto fail;
+ if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+ ssi_signal))
+ goto fail;
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto fail;
+
+ dbus_connection_send(priv->con, msg, NULL);
+ goto out;
+fail:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+out:
+ dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_AP */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index b266bb6..c066944 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
@@ -104,6 +98,9 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -125,9 +122,21 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+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);
@@ -151,6 +160,10 @@ 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);
@@ -172,6 +185,14 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
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);
@@ -200,6 +221,14 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
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);
@@ -230,6 +259,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
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);
@@ -257,9 +289,23 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
DBusError *error,
void *user_data);
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
const char *arg);
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg);
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index aa05f58..5150a76 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -1,14 +1,9 @@
/*
* WPA Supplicant / dbus-based control interface (P2P)
+ * Copyright (c) 2011-2012, Intel Corporation
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -45,7 +40,7 @@ static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
if (!peer_path)
return -1;
- p = strrchr(peer_path, '/');
+ p = os_strrchr(peer_path, '/');
if (!p)
return -1;
p++;
@@ -132,7 +127,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
}
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL);
+ NULL, 0);
os_free(req_dev_types);
return reply;
@@ -351,13 +346,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0,
+ NULL, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
- } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
goto inv_args;
out:
@@ -508,8 +504,8 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
goto inv_args;
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
- persistent_group, join, authorize_only,
- go_intent, freq);
+ persistent_group, 0, join, authorize_only,
+ go_intent, freq, -1, 0, 0, 0);
if (new_pin >= 0) {
char npin[9];
@@ -635,7 +631,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) {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
+ 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -692,7 +689,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
os_strcmp(config_method, "pushbutton"))
return wpas_dbus_error_invalid_args(message, NULL);
- if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
+ if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
+ WPAS_P2P_PD_FOR_GO_NEG) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to send provision discovery request");
@@ -1053,7 +1051,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
* Now construct the peer object paths in a form suitable for
* array_property_getter helper below.
*/
- peer_obj_paths = os_zalloc(num * sizeof(char *));
+ peer_obj_paths = os_calloc(num, sizeof(char *));
if (!peer_obj_paths) {
out_of_mem = 1;
@@ -1513,7 +1511,7 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
if (network_is_persistent_group(ssid))
num++;
- paths = os_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -1820,7 +1818,7 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
num_members = p2p_get_group_num_members(wpa_s->p2p_group);
- paths = os_zalloc(num_members * sizeof(char *));
+ paths = os_calloc(num_members, sizeof(char *));
if (!paths)
goto out_of_memory;
@@ -2073,7 +2071,7 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
goto error;
- if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
@@ -2085,23 +2083,30 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
bonjour = 1;
else
goto error_clear;
- wpa_dbus_dict_entry_clear(&entry);
+ } else if (!os_strcmp(entry.key, "version") &&
+ entry.type == DBUS_TYPE_INT32) {
+ version = entry.uint32_value;
+ } else if (!os_strcmp(entry.key, "service") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ service = os_strdup(entry.str_value);
+ } else if (!os_strcmp(entry.key, "query")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ query = wpabuf_alloc_copy(
+ entry.bytearray_value,
+ entry.array_len);
+ } else if (!os_strcmp(entry.key, "response")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ resp = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
}
+ wpa_dbus_dict_entry_clear(&entry);
}
if (upnp == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (!os_strcmp(entry.key, "version") &&
- entry.type == DBUS_TYPE_INT32)
- version = entry.uint32_value;
- else if (!os_strcmp(entry.key, "service") &&
- entry.type == DBUS_TYPE_STRING)
- service = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- }
if (version <= 0 || service == NULL)
goto error;
@@ -2109,37 +2114,15 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
goto error;
os_free(service);
+ service = NULL;
} else if (bonjour == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (!os_strcmp(entry.key, "query")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
- goto error_clear;
- query = wpabuf_alloc_copy(
- entry.bytearray_value,
- entry.array_len);
- } else if (!os_strcmp(entry.key, "response")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
- goto error_clear;
- resp = wpabuf_alloc_copy(entry.bytearray_value,
- entry.array_len);
- }
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (query == NULL || resp == NULL)
goto error;
- if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
- wpabuf_free(query);
- wpabuf_free(resp);
+ if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
goto error;
- }
+ query = NULL;
+ resp = NULL;
} else
goto error;
@@ -2147,6 +2130,9 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
+ os_free(service);
+ wpabuf_free(query);
+ wpabuf_free(resp);
return wpas_dbus_error_invalid_args(message, NULL);
}
@@ -2316,13 +2302,11 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
if (version <= 0 || service == NULL)
goto error;
- ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, addr,
- version,
- service);
+ ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
} else {
if (tlv == NULL)
goto error;
- ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
+ ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
wpabuf_free(tlv);
}
@@ -2423,7 +2407,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
if (req == 0)
goto error;
- if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long) req))
+ if (!wpas_p2p_sd_cancel_request(wpa_s, req))
goto error;
return NULL;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 241dd75..a11b3c8 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -1,15 +1,9 @@
-
/*
* WPA Supplicant / dbus-based control interface for p2p
+ * Copyright (c) 2011-2012, Intel Corporation
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef 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 a72cfb3..4ad5e7e 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -279,7 +273,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
ret = wpa_supplicant_ap_wps_pin(wpa_s,
params.bssid,
params.pin,
- npin, sizeof(npin));
+ npin, sizeof(npin), 0);
else
#endif /* CONFIG_AP */
{
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index e254365..e26086d 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -596,11 +590,11 @@ int wpa_dbus_unregister_object_per_iface(
if (!obj_desc) {
wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
"private data: %s", __func__, path);
- } else {
- eloop_cancel_timeout(flush_object_timeout_handler, con,
- obj_desc);
+ return 0;
}
+ eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
+
if (!dbus_connection_unregister_object_path(con, path))
return -1;
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index d6e7b48..6d31ad5 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WPA_DBUS_CTRL_H
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index d443269..3b090c0 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index d255e14..85d8a78 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -23,7 +17,6 @@
#include "../bss.h"
#include "dbus_old.h"
#include "dbus_old_handlers.h"
-#include "dbus_common.h"
#include "dbus_common_i.h"
@@ -275,10 +268,12 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
reply = wpas_dbus_iface_get_state(message, wpa_s);
else if (!strcmp(method, "scanning"))
reply = wpas_dbus_iface_get_scanning(message, wpa_s);
+#ifndef CONFIG_NO_CONFIG_BLOBS
else if (!strcmp(method, "setBlobs"))
reply = wpas_dbus_iface_set_blobs(message, wpa_s);
else if (!strcmp(method, "removeBlobs"))
reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
#ifdef CONFIG_WPS
else if (!os_strcmp(method, "wpsPbc"))
reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h
index 9523867..e668231 100644
--- a/wpa_supplicant/dbus/dbus_old.h
+++ b/wpa_supplicant/dbus/dbus_old.h
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_DBUS_H
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index a7eabf3..7c4630e 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -31,10 +25,6 @@
#include "dbus_old_handlers.h"
#include "dbus_dict_helpers.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
/**
* wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
* @message: Pointer to incoming dbus message this error refers to
@@ -229,7 +219,7 @@ DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
goto out;
}
- if (!wpa_supplicant_remove_iface(global, wpa_s)) {
+ if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_new_success_reply(message);
} else {
reply = dbus_message_new_error(message,
@@ -337,7 +327,7 @@ DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return wpas_dbus_new_success_reply(message);
}
@@ -545,7 +535,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = {"CCMP", "TKIP", "NONE"};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "pairwise", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -588,7 +578,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -638,7 +628,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "key_mgmt", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -689,7 +679,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = { "RSN", "WPA" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "proto", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -726,7 +716,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = { "OPEN", "SHARED", "LEAP" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "auth_alg", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -1306,6 +1296,8 @@ DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
/**
* wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
* @message: Pointer to incoming dbus message
@@ -1435,6 +1427,8 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
return wpas_dbus_new_success_reply(message);
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
/**
* wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h
index 009e807..825bc6d 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.h
+++ b/wpa_supplicant/dbus/dbus_old_handlers.h
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_DBUS_HANDLERS_H
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index c04b844..bb79382 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface (WPS)
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 0476bc3..6684782 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -20,63 +20,6 @@
# used to fix build issues on such systems (krb5.h not found).
#CFLAGS += -I/usr/include/kerberos
-# Example configuration for various cross-compilation platforms
-
-#### sveasoft (e.g., for Linksys WRT54G) ######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
-#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
-###############################################################################
-
-#### openwrt (e.g., for Linksys WRT54G) #######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
-# -I../WRT54GS/release/src/include
-#LIBS = -lssl
-###############################################################################
-
-
-# Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
-
-# Driver interface for Agere driver
-#CONFIG_DRIVER_HERMES=y
-# Change include directories to match with the local setup
-#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
-#CFLAGS += -I../../include/wireless
-
-# Driver interface for madwifi driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_MADWIFI=y
-# Set include directory to the madwifi source tree
-#CFLAGS += -I../../madwifi
-
-# Driver interface for ndiswrapper
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_NDISWRAPPER=y
-
-# Driver interface for Atmel driver
-CONFIG_DRIVER_ATMEL=y
-
-# Driver interface for old Broadcom driver
-# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
-# Linux wireless extensions and does not need (or even work) with the old
-# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
-#CONFIG_DRIVER_BROADCOM=y
-# Example path for wlioctl.h; change to match your configuration
-#CFLAGS += -I/opt/WRT54GS/release/src/include
-
-# Driver interface for Intel ipw2100/2200 driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_IPW=y
-
-# Driver interface for Ralink driver
-#CONFIG_DRIVER_RALINK=y
-
# Driver interface for generic Linux wireless extensions
# Note: WEXT is deprecated in the current Linux kernel version and no new
# functionality is added to it. nl80211-based interface is the new
@@ -88,6 +31,19 @@ CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -147,10 +103,9 @@ CONFIG_EAP_PEAP=y
CONFIG_EAP_TTLS=y
# EAP-FAST
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
-# to add the needed functions.
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
#CONFIG_EAP_FAST=y
# EAP-GTC
@@ -204,10 +159,15 @@ CONFIG_EAP_LEAP=y
# Disable credentials for an open network by default when acting as a WPS
# registrar.
#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
+# EAP-EKE
+#CONFIG_EAP_EKE=y
+
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@@ -220,6 +180,12 @@ CONFIG_SMARTCARD=y
# Enable this if EAP-SIM or EAP-AKA is included
#CONFIG_PCSC=y
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
# Development testing
#CONFIG_EAPOL_TEST=y
@@ -227,6 +193,7 @@ CONFIG_SMARTCARD=y
# unix = UNIX domain sockets (default for Linux/*BSD)
# udp = UDP sockets using localhost (127.0.0.1)
# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
# y = use default (backwards compatibility)
# If this option is commented out, control interface is not included in the
# build.
@@ -252,11 +219,6 @@ CONFIG_CTRL_IFACE=y
# 35-50 kB in code size.
#CONFIG_NO_WPA=y
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=y
-
# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
# This option can be used to reduce code size by removing support for
# converting ASCII passphrases into PSK. If this functionality is removed, the
@@ -300,9 +262,11 @@ CONFIG_BACKEND=file
# Select event loop implementation
# eloop = select() loop (default)
# eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
#CONFIG_ELOOP=eloop
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
# Select layer 2 packet implementation
# linux = Linux packet socket (default)
# pcap = libpcap/libdnet/WinPcap
@@ -315,9 +279,7 @@ CONFIG_BACKEND=file
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
+# IEEE 802.11w (management frame protection), also known as PMF
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
@@ -335,6 +297,13 @@ CONFIG_PEERKEY=y
# sent prior to negotiating which version will be used)
#CONFIG_TLSV11=y
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
+
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
@@ -400,6 +369,16 @@ CONFIG_PEERKEY=y
# Set syslog facility for debug messages
#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+#CONFIG_ANDROID_LOG=y
+
# Enable privilege separation (see README 'Privilege separation' for details)
#CONFIG_PRIVSEP=y
@@ -459,8 +438,60 @@ CONFIG_PEERKEY=y
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
#CONFIG_IEEE80211N=y
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
# Interworking (IEEE 802.11u)
# This can be used to enable functionality to improve interworking with
# external networks (GAS/ANQP to learn more about the networks and network
# selection based on available credentials).
#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Disable roaming in wpa_supplicant
+#CONFIG_NO_ROAMING=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Enable TDLS support
+#CONFIG_TDLS=y
+
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+#CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
diff --git a/wpa_supplicant/doc/docbook/Makefile b/wpa_supplicant/doc/docbook/Makefile
index aaeee2e..82f9de3 100644
--- a/wpa_supplicant/doc/docbook/Makefile
+++ b/wpa_supplicant/doc/docbook/Makefile
@@ -7,6 +7,7 @@ FILES += wpa_passphrase
FILES += wpa_priv
FILES += wpa_supplicant.conf
FILES += wpa_supplicant
+FILES += eapol_test
man:
for i in $(FILES); do docbook2man $$i.sgml; done
@@ -20,7 +21,7 @@ pdf:
clean:
- rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8
+ rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8 eapol_test.8
rm -f wpa_supplicant.conf.5
rm -f manpage.links manpage.refs
rm -f $(FILES:%=%.pdf)
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
new file mode 100644
index 0000000..fec174b
--- /dev/null
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -0,0 +1,205 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refmeta>
+ <refentrytitle>eapol_test</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>eapol_test</refname>
+
+ <refpurpose>EAP peer and RADIUS client testing</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>eapol_test</command>
+ <arg>-nWS</arg>
+ <arg>-c<replaceable>config file</replaceable></arg>
+ <arg>-a<replaceable>server IP address</replaceable></arg>
+ <arg>-A<replaceable>client IP address</replaceable></arg>
+ <arg>-p<replaceable>UDP port</replaceable></arg>
+ <arg>-s<replaceable>shared secret</replaceable></arg>
+ <arg>-r<replaceable>re-authentications</replaceable></arg>
+ <arg>-t<replaceable>timeout</replaceable></arg>
+ <arg>-C<replaceable>Connect-Info</replaceable></arg>
+ <arg>-M<replaceable>MAC address</replaceable></arg>
+ <arg>-o<replaceable>file</replaceable></arg>
+ <arg>-N<replaceable>attr spec</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>eapol_test scard</command>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>eapol_test sim</command>
+ <arg>PIN</arg>
+ <arg>num triplets</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para>eapol_test is a program that links together the same EAP
+ peer implementation that wpa_supplicant is using and the RADIUS
+ authentication client code from hostapd. In addition, it has
+ minimal glue code to combine these two components in similar
+ ways to IEEE 802.1X/EAPOL Authenticator state machines. In other
+ words, it integrates IEEE 802.1X Authenticator (normally, an
+ access point) and IEEE 802.1X Supplicant (normally, a wireless
+ client) together to generate a single program that can be used to
+ test EAP methods without having to setup an access point and a
+ wireless client.</para>
+
+ <para>The main uses for eapol_test are in interoperability testing
+ of EAP methods against RADIUS servers and in development testing
+ for new EAP methods. It can be easily used to automate EAP testing
+ for interoperability and regression since the program can be run
+ from shell scripts without require additional test components apart
+ from a RADIUS server. For example, the automated EAP tests described
+ in eap_testing.txt are implemented with eapol_test. Similarly,
+ eapol_test could be used to implement an automated regression
+ test suite for a RADIUS authentication server.</para>
+
+
+ <para>As an example:</para>
+
+<blockquote><programlisting>
+eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
+</programlisting></blockquote>
+
+ <para>tries to complete EAP authentication based on the network
+ configuration from test.conf against the RADIUS server running
+ on the local host. A re-authentication is triggered to test fast
+ re-authentication. The configuration file uses the same format for
+ network blocks as wpa_supplicant.</para>
+
+ </refsect1>
+ <refsect1>
+ <title>Command Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term>-c configuration file path</term>
+
+ <listitem><para>A configuration to use. The configuration should
+ use the same format for network blocks as wpa_supplicant.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a AS address</term>
+
+ <listitem><para>IP address of the authentication server. The
+ default is '127.0.0.1'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-A client address</term>
+
+ <listitem><para>IP address of the client. The default is to
+ select an address automatically.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-p AS port</term>
+
+ <listitem><para>UDP port of the authentication server. The
+ default is '1812'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s AS secret</term>
+
+ <listitem><para>Shared secret with the authentication server.
+ The default is 'radius'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-r count</term>
+
+ <listitem><para>Number of reauthentications.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-t timeout</term>
+
+ <listitem><para>Timeout in seconds. The default is 30.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-C info</term>
+
+ <listitem><para>RADIUS Connect-Info. The default is
+ 'CONNECT 11Mbps 802.11b'.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-M mac address</term>
+
+ <listitem><para>Client MAC address (Calling-Station-Id). The
+ default is '02:00:00:00:00:01'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o file</term>
+
+ <listitem><para>Location to write out server certificate.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-N attr spec</term>
+
+ <listitem><para>Send arbitrary attribute specific by
+ attr_id:syntax:value, or attr_id alone. attr_id should be the numeric
+ ID of the attribute, and syntax should be one of 's' (string),
+ 'd' (integer), or 'x' (octet string). The value is the attribute value
+ to send. When attr_id is given alone, NULL is used as the attribute
+ value. Multiple attributes can be specified by using the option
+ several times.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-n</term>
+
+ <listitem><para>Indicates that no MPPE keys are expected.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-W</term>
+
+ <listitem><para>Wait for a control interface monitor before starting.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-S</term>
+
+ <listitem><para>Save configuration after authentication.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2014,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index f47235b..860b5a0 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,12 +90,12 @@
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2014,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index 1fe98f4..142e1ab 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -15,10 +15,12 @@
<cmdsynopsis>
<command>wpa_cli</command>
<arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+ <arg>-g <replaceable>path to global ctrl_interface socket</replaceable></arg>
<arg>-i <replaceable>ifname</replaceable></arg>
<arg>-hvB</arg>
<arg>-a <replaceable>action file</replaceable></arg>
<arg>-P <replaceable>pid file</replaceable></arg>
+ <arg>-G <replaceable>ping interval</replaceable></arg>
<arg><replaceable>command ...</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -111,6 +113,14 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
</varlistentry>
<varlistentry>
+ <term>-g control socket path</term>
+
+ <listitem><para>Connect to the global control socket at the
+ indicated path rather than an interface-specific control
+ socket.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-i ifname</term>
<listitem><para>Specify the interface that is being
@@ -161,6 +171,13 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
</varlistentry>
<varlistentry>
+ <term>-G ping interval</term>
+
+ <listitem><para>Set the interval (in seconds) at which
+ wpa_cli pings the supplicant.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>command</term>
<listitem><para>Run a command. The available commands are
@@ -328,12 +345,12 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2014,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index 41b5849..f6ef8f1 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -74,12 +74,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2014,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 402ea09..3b4360b 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,12 +62,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2014,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 89b8a92..9c114cc 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,12 +137,12 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2014,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 0ab4e15..182060d 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -12,7 +12,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>wpa_supplicant</command>
- <arg>-BddfhKLqqtuvW</arg>
+ <arg>-BddfhKLqqsTtuvW</arg>
<arg>-i<replaceable>ifname</replaceable></arg>
<arg>-c<replaceable>config file</replaceable></arg>
<arg>-D<replaceable>driver</replaceable></arg>
@@ -246,28 +246,6 @@
<variablelist>
<varlistentry>
- <term>hostap</term>
- <listitem>
- <para>(default) Host AP driver (Intersil Prism2/2.5/3).
- (this can also be used with Linuxant DriverLoader).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>hermes</term>
- <listitem>
- <para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>madwifi</term>
- <listitem>
- <para>MADWIFI 802.11 support (Atheros, etc.).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>wext</term>
<listitem>
<para>Linux wireless extensions (generic).</para>
@@ -275,13 +253,6 @@
</varlistentry>
<varlistentry>
- <term>broadcom</term>
- <listitem>
- <para>Broadcom wl.o driver.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>wired</term>
<listitem>
<para>wpa_supplicant wired Ethernet driver</para>
@@ -373,9 +344,20 @@
</varlistentry>
<varlistentry>
+ <term>-e entropy file</term>
+ <listitem>
+ <para>File for <command>wpa_supplicant</command> to use to
+ maintain its internal entropy store in over restarts.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-f output file</term>
<listitem>
- <para>Log output to specified file instead of stdout.</para>
+ <para>Log output to specified file instead of stdout. (This
+ is only available if <command>wpa_supplicant</command> was
+ built with the <literal>CONFIG_DEBUG_FILE</literal>
+ option.)</para>
</listitem>
</varlistentry>
@@ -411,7 +393,23 @@
<varlistentry>
<term>-L</term>
<listitem>
- <para>Show license (GPL and BSD).</para>
+ <para>Show license (BSD).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o override driver</term>
+ <listitem>
+ <para>Override the driver parameter for new
+ interfaces.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O override ctrl_interface</term>
+ <listitem>
+ <para>Override the ctrl_interface parameter for new
+ interfaces.</para>
</listitem>
</varlistentry>
@@ -438,10 +436,40 @@
</varlistentry>
<varlistentry>
+ <term>-s</term>
+ <listitem>
+ <para>Log output to syslog instead of stdout. (This is only
+ available if <command>wpa_supplicant</command> was built
+ with the <literal>CONFIG_DEBUG_SYSLOG</literal>
+ option.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-T</term>
+ <listitem>
+ <para>Log output to Linux tracing in addition to any other
+ destinations. (This is only available
+ if <command>wpa_supplicant</command> was built with
+ the <literal>CONFIG_DEBUG_LINUX_TRACING</literal>
+ option.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-t</term>
+ <listitem>
+ <para>Include timestamp in debug messages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-u</term>
<listitem>
- <para>Enabled DBus control interface. If enabled, interface
- definitions may be omitted.</para>
+ <para>Enable DBus control interface. If enabled, interface
+ definitions may be omitted. (This is only available
+ if <command>wpa_supplicant</command> was built with
+ the <literal>CONFIG_DBUS</literal> option.)</para>0
</listitem>
</varlistentry>
@@ -506,8 +534,8 @@ wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
<blockquote><programlisting>
wpa_supplicant \
- -c wpa1.conf -i wlan0 -D hostap -N \
- -c wpa2.conf -i ath0 -D madwifi
+ -c wpa1.conf -i wlan0 -D nl80211 -N \
+ -c wpa2.conf -i ath0 -D wext
</programlisting></blockquote>
</refsect1>
@@ -537,86 +565,6 @@ wpa_supplicant \
<title>Supported Drivers</title>
<variablelist>
<varlistentry>
- <term>Host AP driver for Prism2/2.5/3 (development
- snapshot/v0.2.x)</term>
- <listitem>
- <para> (http://hostap.epitest.fi/) Driver needs to be set in
- Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>).
- Please note that station firmware version needs to be 1.7.0 or
- newer to work in WPA mode.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Linuxant DriverLoader</term>
- <listitem>
- <para>(http://www.linuxant.com/driverloader/)
- with Windows NDIS driver for your wlan card supporting WPA.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Agere Systems Inc. Linux Driver</term>
- <listitem>
- <para> (http://www.agere.com/support/drivers/) Please note
- that the driver interface file (driver_hermes.c) and hardware
- specific include files are not included in the wpa_supplicant
- distribution. You will need to copy these from the source
- package of the Agere driver.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>madwifi driver for cards based on Atheros chip set (ar521x)</term>
- <listitem>
- <para> (http://sourceforge.net/projects/madwifi/) Please
- note that you will need to modify the wpa_supplicant .config
- file to use the correct path for the madwifi driver root
- directory (CFLAGS += -I../madwifi/wpa line in example
- defconfig).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Linux ndiswrapper</term>
- <listitem>
- <para> (http://ndiswrapper.sourceforge.net/) with Windows
- NDIS driver.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Broadcom wl.o driver</term>
- <listitem>
- <para> This is a generic Linux driver for Broadcom IEEE
- 802.11a/g cards. However, it is proprietary driver that is
- not publicly available except for couple of exceptions, mainly
- Broadcom-based APs/wireless routers that use Linux. The driver
- binary can be downloaded, e.g., from Linksys support site
- (http://www.linksys.com/support/gpl.asp) for Linksys
- WRT54G. The GPL tarball includes cross-compiler and the needed
- header file, wlioctl.h, for compiling wpa_supplicant. This
- driver support in wpa_supplicant is expected to work also with
- other devices based on Broadcom driver (assuming the driver
- includes client mode support).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term> Intel ipw2100 driver</term>
- <listitem>
- <para> (http://sourceforge.net/projects/ipw2100/)</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Intel ipw2200 driver</term>
- <listitem>
- <para> (http://sourceforge.net/projects/ipw2200/)</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>Linux wireless extensions</term>
<listitem>
<para>In theory, any driver that supports Linux wireless
@@ -788,12 +736,12 @@ fi
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2014,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 9828aff..0691b6c 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -2,14 +2,8 @@
* wpa_supplicant - Internal driver interface wrappers
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DRIVER_I_H
@@ -123,11 +117,16 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid)
static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ if (alg != WPA_ALG_NONE) {
+ if (key_idx >= 0 && key_idx <= 6)
+ wpa_s->keys_cleared &= ~BIT(key_idx);
+ else
+ wpa_s->keys_cleared = 0;
+ }
if (wpa_s->driver->set_key) {
- wpa_s->keys_cleared = 0;
return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
alg, addr, key_idx, set_tx,
seq, seq_len, key, key_len);
@@ -135,22 +134,23 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
return -1;
}
-static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
- const u8 *addr, int reason_code)
+static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int reason_code)
{
- if (wpa_s->driver->deauthenticate) {
- return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr,
- reason_code);
+ if (wpa_s->driver->sta_deauth) {
+ return wpa_s->driver->sta_deauth(wpa_s->drv_priv,
+ wpa_s->own_addr, addr,
+ reason_code);
}
return -1;
}
-static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
- const u8 *addr, int reason_code)
+static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int reason_code)
{
- if (wpa_s->driver->disassociate) {
- return wpa_s->driver->disassociate(wpa_s->drv_priv, addr,
- reason_code);
+ if (wpa_s->driver->deauthenticate) {
+ return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr,
+ reason_code);
}
return -1;
}
@@ -262,11 +262,11 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
- const u8 *data, size_t data_len)
+ const u8 *data, size_t data_len, int noack)
{
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
- data, data_len);
+ data, data_len, noack);
return -1;
}
@@ -385,7 +385,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);
+ if_addr, bridge, 0);
return -1;
}
@@ -469,6 +469,15 @@ static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
+ struct hostap_sta_driver_data *sta)
+{
+ if (wpa_s->driver->read_sta_data)
+ return wpa_s->driver->read_sta_data(wpa_s->drv_priv, sta,
+ wpa_s->bssid);
+ return -1;
+}
+
static inline int wpa_drv_set_ap_wps_ie(struct wpa_supplicant *wpa_s,
const struct wpabuf *beacon,
const struct wpabuf *proberesp,
@@ -512,162 +521,87 @@ static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu)
return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu);
}
-static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s,
- unsigned int timeout, int type)
-{
- if (!wpa_s->driver->p2p_find)
- return -1;
- return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type);
-}
-
-static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s->driver->p2p_stop_find)
- return -1;
- return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv);
-}
-
-static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s,
- unsigned int timeout)
-{
- if (!wpa_s->driver->p2p_listen)
- return -1;
- return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout);
-}
-
-static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr, int wps_method,
- int go_intent,
- const u8 *own_interface_addr,
- unsigned int force_freq,
- int persistent_group)
-{
- if (!wpa_s->driver->p2p_connect)
- return -1;
- return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr,
- wps_method, go_intent,
- own_interface_addr, force_freq,
- persistent_group);
-}
-
-static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr)
-{
- if (!wpa_s->driver->wps_success_cb)
- return -1;
- return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr);
-}
-
-static inline int
-wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
+ const u8 *dst, u8 action_code,
+ u8 dialog_token, u16 status_code,
+ const u8 *buf, size_t len)
{
- if (!wpa_s->driver->p2p_group_formation_failed)
- return -1;
- return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv);
+ if (wpa_s->driver->send_tdls_mgmt) {
+ return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
+ action_code, dialog_token,
+ status_code, buf, len);
+ }
+ return -1;
}
-static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,
- const struct p2p_params *params)
+static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
+ enum tdls_oper oper, const u8 *peer)
{
- if (!wpa_s->driver->p2p_set_params)
+ if (!wpa_s->driver->tdls_oper)
return -1;
- return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params);
+ return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
}
-static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr,
- u16 config_methods, int join)
+#ifdef ANDROID
+static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf, size_t buf_len)
{
- if (!wpa_s->driver->p2p_prov_disc_req)
+ if (!wpa_s->driver->driver_cmd)
return -1;
- return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
- config_methods, join);
+ return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
}
+#endif /* ANDROID */
-static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
- const u8 *dst,
- const struct wpabuf *tlvs)
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+ const u8 *kek, const u8 *kck,
+ const u8 *replay_ctr)
{
- if (!wpa_s->driver->p2p_sd_request)
- return 0;
- return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs);
+ if (!wpa_s->driver->set_rekey_info)
+ return;
+ wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
}
-static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s,
- u64 req)
+static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
+ int disabled)
{
- if (!wpa_s->driver->p2p_sd_cancel_request)
+ if (!wpa_s->driver->radio_disable)
return -1;
- return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req);
+ return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
}
-static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s,
- int freq, const u8 *dst,
- u8 dialog_token,
- const struct wpabuf *resp_tlvs)
+static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings)
{
- if (!wpa_s->driver->p2p_sd_response)
+ if (!wpa_s->driver->switch_channel)
return -1;
- return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst,
- dialog_token, resp_tlvs);
+ return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings);
}
-static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
+ enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len)
{
- if (!wpa_s->driver->p2p_service_update)
+ if (!wpa_s->driver->wnm_oper)
return -1;
- return wpa_s->driver->p2p_service_update(wpa_s->drv_priv);
+ return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
+ buf_len);
}
-static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s,
- const u8 *addr)
+static inline int wpa_drv_status(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
{
- if (!wpa_s->driver->p2p_reject)
+ if (!wpa_s->driver->status)
return -1;
- return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr);
+ return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
}
-static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
- const u8 *peer, int role, const u8 *bssid,
- const u8 *ssid, size_t ssid_len,
- const u8 *go_dev_addr,
- int persistent_group)
+static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
+ const u8 *qos_map_set, u8 qos_map_set_len)
{
- if (!wpa_s->driver->p2p_invite)
+ if (!wpa_s->driver->set_qos_map)
return -1;
- return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid,
- ssid, ssid_len, go_dev_addr,
- persistent_group);
-}
-
-static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
- const u8 *dst, u8 action_code,
- u8 dialog_token, u16 status_code,
- const u8 *buf, size_t len)
-{
- if (wpa_s->driver->send_tdls_mgmt) {
- return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
- action_code, dialog_token,
- status_code, buf, len);
- }
- return -1;
-}
-
-static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
- enum tdls_oper oper, const u8 *peer)
-{
- if (!wpa_s->driver->tdls_oper)
- return -1;
- return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
-}
-
-static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
- const u8 *kek, const u8 *kck,
- const u8 *replay_ctr)
-{
- if (!wpa_s->driver->set_rekey_info)
- return;
- wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+ return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set,
+ qos_map_set_len);
}
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eap_proxy_dummy.mk b/wpa_supplicant/eap_proxy_dummy.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/wpa_supplicant/eap_proxy_dummy.mk
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index e5f43aa..6cd2fc5 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -2,14 +2,8 @@
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -17,6 +11,7 @@
#include "common.h"
#include "eap_peer/eap_methods.h"
#include "eap_server/eap_methods.h"
+#include "wpa_supplicant_i.h"
/**
@@ -40,6 +35,11 @@ int eap_register_methods(void)
ret = eap_peer_tls_register();
#endif /* EAP_TLS */
+#ifdef EAP_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_peer_unauth_tls_register();
+#endif /* EAP_UNAUTH_TLS */
+
#ifdef EAP_MSCHAPv2
if (ret == 0)
ret = eap_peer_mschapv2_register();
@@ -135,6 +135,11 @@ int eap_register_methods(void)
ret = eap_peer_pwd_register();
#endif /* EAP_PWD */
+#ifdef EAP_EKE
+ if (ret == 0)
+ ret = eap_peer_eke_register();
+#endif /* EAP_EKE */
+
#ifdef EAP_SERVER_IDENTITY
if (ret == 0)
ret = eap_server_identity_register();
@@ -150,6 +155,11 @@ int eap_register_methods(void)
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
+#ifdef EAP_SERVER_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 024903c..ac0ab0b 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant - test code
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
* Not used in production version.
@@ -19,6 +13,7 @@
#include <assert.h>
#include "common.h"
+#include "utils/ext_password.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
@@ -26,18 +21,15 @@
#include "eloop.h"
#include "utils/base64.h"
#include "rsn_supp/wpa.h"
-#include "eap_peer/eap_i.h"
#include "wpa_supplicant_i.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "common/wpa_ctrl.h"
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
+#include "wpas_glue.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
struct wpa_driver_ops *wpa_drivers[] = { NULL };
@@ -61,9 +53,8 @@ struct eapol_test_data {
struct radius_client_data *radius;
struct hostapd_radius_servers *radius_conf;
- u8 *last_eap_radius; /* last received EAP Response from Authentication
- * Server */
- size_t last_eap_radius_len;
+ /* last received EAP Response from Authentication Server */
+ struct wpabuf *last_eap_radius;
u8 authenticator_pmk[PMK_LEN];
size_t authenticator_pmk_len;
@@ -104,7 +95,7 @@ static int add_extra_attr(struct radius_msg *msg,
size_t len;
char *pos;
u32 val;
- char buf[128];
+ char buf[RADIUS_MAX_ATTR_LEN + 1];
switch (attr->syntax) {
case 's':
@@ -120,7 +111,7 @@ static int add_extra_attr(struct radius_msg *msg,
if (pos[0] == '0' && pos[1] == 'x')
pos += 2;
len = os_strlen(pos);
- if ((len & 1) || (len / 2) > sizeof(buf)) {
+ if ((len & 1) || (len / 2) > RADIUS_MAX_ATTR_LEN) {
printf("Invalid extra attribute hexstring\n");
return -1;
}
@@ -177,7 +168,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
const u8 *eap, size_t len)
{
struct radius_msg *msg;
- char buf[128];
+ char buf[RADIUS_MAX_ATTR_LEN + 1];
const struct eap_hdr *hdr;
const u8 *pos;
@@ -374,10 +365,11 @@ static int eapol_test_compare_pmk(struct eapol_test_data *e)
}
-static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
+static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result,
+ void *ctx)
{
struct eapol_test_data *e = ctx;
- printf("eapol_sm_cb: success=%d\n", success);
+ printf("eapol_sm_cb: result=%d\n", result);
e->eapol_test_num_reauths--;
if (e->eapol_test_num_reauths < 0)
eloop_terminate();
@@ -402,6 +394,54 @@ static void eapol_test_write_cert(FILE *f, const char *subject,
}
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+ const char *default_txt)
+{
+ struct eapol_test_data *e = ctx;
+ struct wpa_supplicant *wpa_s = e->wpa_s;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const char *field_name, *txt = NULL;
+ char *buf;
+ size_t buflen;
+ int len;
+
+ if (ssid == NULL)
+ return;
+
+ field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+ &txt);
+ if (field_name == NULL) {
+ wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+ field);
+ return;
+ }
+
+ buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ len = os_snprintf(buf, buflen,
+ WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+ field_name, ssid->id, txt);
+ if (len < 0 || (size_t) len >= buflen) {
+ os_free(buf);
+ return;
+ }
+ if (ssid->ssid && buflen > len + ssid->ssid_len) {
+ os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+ len += ssid->ssid_len;
+ buf[len] = '\0';
+ }
+ buf[buflen - 1] = '\0';
+ wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+ os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_test_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
const char *cert_hash,
const struct wpabuf *cert)
@@ -435,6 +475,37 @@ static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
}
+static void eapol_test_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct eapol_test_data *e = ctx;
+ struct wpa_supplicant *wpa_s = e->wpa_s;
+ char *str;
+ int res;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+ id, len);
+
+ if (wpa_s->current_ssid == NULL)
+ return;
+
+ if (id == NULL) {
+ if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ "NULL", 0) < 0)
+ return;
+ } else {
+ str = os_malloc(len * 2 + 1);
+ if (str == NULL)
+ return;
+ wpa_snprintf_hex(str, len * 2 + 1, id, len);
+ res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ str, 0);
+ os_free(str);
+ if (res < 0)
+ return;
+ }
+}
+
+
static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -460,8 +531,10 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->eap_param_needed = eapol_test_eap_param_needed;
ctx->cert_cb = eapol_test_cert_cb;
ctx->cert_in_cb = 1;
+ ctx->set_anon_id = eapol_test_set_anon_id;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
@@ -476,6 +549,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
eapol_conf.required_keys = 0;
eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
+ eapol_conf.external_sim = wpa_s->conf->external_sim;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
@@ -494,7 +568,7 @@ static void test_eapol_clean(struct eapol_test_data *e,
struct extra_radius_attr *p, *prev;
radius_client_deinit(e->radius);
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
radius_msg_free(e->last_recv_radius);
e->last_recv_radius = NULL;
os_free(e->eap_identity);
@@ -512,6 +586,10 @@ static void test_eapol_clean(struct eapol_test_data *e,
wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
wpa_s->ctrl_iface = NULL;
}
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+
wpa_config_free(wpa_s->conf);
p = e->extra_attrs;
@@ -580,9 +658,8 @@ static char *eap_type_text(u8 type)
static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
{
- u8 *eap;
- size_t len;
- struct eap_hdr *hdr;
+ struct wpabuf *eap;
+ const struct eap_hdr *hdr;
int eap_type = -1;
char buf[64];
struct radius_msg *msg;
@@ -592,30 +669,29 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
msg = e->last_recv_radius;
- eap = radius_msg_get_eap(msg, &len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
/* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
wpa_printf(MSG_DEBUG, "could not extract "
"EAP-Message from RADIUS message");
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
e->last_eap_radius = NULL;
- e->last_eap_radius_len = 0;
return;
}
- if (len < sizeof(*hdr)) {
+ if (wpabuf_len(eap) < sizeof(*hdr)) {
wpa_printf(MSG_DEBUG, "too short EAP packet "
"received from authentication server");
- os_free(eap);
+ wpabuf_free(eap);
return;
}
- if (len > sizeof(*hdr))
- eap_type = eap[sizeof(*hdr)];
+ if (wpabuf_len(eap) > sizeof(*hdr))
+ eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
- hdr = (struct eap_hdr *) eap;
+ hdr = wpabuf_head(eap);
switch (hdr->code) {
case EAP_CODE_REQUEST:
os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
@@ -638,7 +714,7 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
break;
default:
os_strlcpy(buf, "unknown EAP code", sizeof(buf));
- wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len);
+ wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
break;
}
wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
@@ -647,20 +723,21 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
e->last_eap_radius = eap;
- e->last_eap_radius_len = len;
{
struct ieee802_1x_hdr *dot1x;
- dot1x = os_malloc(sizeof(*dot1x) + len);
+ dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap));
assert(dot1x != NULL);
dot1x->version = EAPOL_VERSION;
dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
- dot1x->length = htons(len);
- os_memcpy((u8 *) (dot1x + 1), eap, len);
+ dot1x->length = htons(wpabuf_len(eap));
+ os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap),
+ wpabuf_len(eap));
eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
- (u8 *) dot1x, sizeof(*dot1x) + len);
+ (u8 *) dot1x,
+ sizeof(*dot1x) + wpabuf_len(eap));
os_free(dot1x);
}
}
@@ -864,7 +941,7 @@ static int scard_test(void)
unsigned char aka_ik[IK_LEN];
unsigned char aka_ck[CK_LEN];
- scard = scard_init(SCARD_TRY_BOTH);
+ scard = scard_init(NULL);
if (scard == NULL)
return -1;
if (scard_set_pin(scard, "1234")) {
@@ -879,6 +956,9 @@ static int scard_test(void)
wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len);
/* NOTE: Permanent Username: 1 | IMSI */
+ wpa_printf(MSG_DEBUG, "SCARD: MNC length %d",
+ scard_get_mnc_len(scard));
+
os_memset(_rand, 0, sizeof(_rand));
if (scard_gsm_auth(scard, _rand, sres, kc))
goto failed;
@@ -961,7 +1041,7 @@ static int scard_get_triplets(int argc, char *argv[])
wpa_debug_level = 99;
}
- scard = scard_init(SCARD_GSM_SIM_ONLY);
+ scard = scard_init(NULL);
if (scard == NULL) {
printf("Failed to open smartcard connection\n");
return -1;
@@ -1063,6 +1143,7 @@ static void usage(void)
int main(int argc, char *argv[])
{
+ struct wpa_global global;
struct wpa_supplicant wpa_s;
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
char *as_addr = "127.0.0.1";
@@ -1141,7 +1222,7 @@ int main(int argc, char *argv[])
wait_for_monitor++;
break;
case 'N':
- p1 = os_zalloc(sizeof(p1));
+ p1 = os_zalloc(sizeof(*p1));
if (p1 == NULL)
break;
if (!p)
@@ -1199,9 +1280,13 @@ int main(int argc, char *argv[])
return -1;
}
+ os_memset(&global, 0, sizeof(global));
os_memset(&wpa_s, 0, sizeof(wpa_s));
+ wpa_s.global = &global;
eapol_test.wpa_s = &wpa_s;
- wpa_s.conf = wpa_config_read(conf);
+ dl_list_init(&wpa_s.bss);
+ dl_list_init(&wpa_s.bss_id);
+ wpa_s.conf = wpa_config_read(conf, NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", conf);
return -1;
@@ -1231,6 +1316,9 @@ int main(int argc, char *argv[])
if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
return -1;
+ if (wpas_init_ext_pw(&wpa_s) < 0)
+ return -1;
+
if (wait_for_monitor)
wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 3368529..a72f2fa 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -29,6 +23,7 @@
#include "eap_peer/eap.h"
#include "ap/hostapd.h"
#include "p2p/p2p.h"
+#include "wnm_sta.h"
#include "notify.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -41,15 +36,58 @@
#include "gas_query.h"
#include "p2p_supplicant.h"
#include "bgscan.h"
+#include "autoscan.h"
#include "ap.h"
#include "bss.h"
#include "scan.h"
#include "offchannel.h"
+#include "interworking.h"
+
+
+#ifndef CONFIG_NO_SCAN_PROCESSING
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+ int new_scan, int own_request);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+
+
+static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct os_reltime now;
+
+ if (ssid == NULL || ssid->disabled_until.sec == 0)
+ return 0;
+
+ os_get_reltime(&now);
+ if (ssid->disabled_until.sec > now.sec)
+ return ssid->disabled_until.sec - now.sec;
+
+ wpas_clear_temp_disabled(wpa_s, ssid, 0);
+
+ return 0;
+}
+
+
+static struct wpa_bss * wpa_supplicant_get_new_bss(
+ struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bss *bss = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid->ssid_len > 0)
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+ if (!bss)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+ return bss;
+}
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid, *old_ssid;
+ struct wpa_bss *bss;
+ int res;
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
return 0;
@@ -63,22 +101,32 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
return -1;
}
- if (ssid->disabled) {
+ if (wpas_network_disabled(wpa_s, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
return -1;
}
+ if (disallowed_bssid(wpa_s, wpa_s->bssid) ||
+ disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed");
+ return -1;
+ }
+
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
+ "disabled for %d second(s)", res);
+ return -1;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
"current AP");
- if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_WPA_NONE |
- WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
u8 wpa_ie[80];
size_t wpa_ie_len = sizeof(wpa_ie);
- wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len);
+ if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+ wpa_ie, &wpa_ie_len) < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites");
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
}
@@ -87,6 +135,18 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
eapol_sm_invalidate_cached_session(wpa_s->eapol);
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
+
+ bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+ if (!bss) {
+ wpa_supplicant_update_scan_results(wpa_s);
+
+ /* Get the BSS from the new scan results */
+ bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+ }
+
+ if (bss)
+ wpa_s->current_bss = bss;
+
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)
@@ -113,6 +173,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
{
int bssid_changed;
+ wnm_bss_keep_alive_deinit(wpa_s);
+
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
wpa_s->ibss_rsn = NULL;
@@ -129,6 +191,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
#ifdef CONFIG_P2P
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
#endif /* CONFIG_P2P */
@@ -149,6 +214,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
wpa_s->ap_ies_from_associnfo = 0;
+ wpa_s->current_ssid = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->key_mgmt = 0;
}
@@ -233,9 +301,10 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
{
#ifdef IEEE8021X_EAPOL
#ifdef PCSC_FUNCS
- int aka = 0, sim = 0, type;
+ int aka = 0, sim = 0;
- if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+ if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL ||
+ wpa_s->conf->external_sim)
return 0;
if (ssid->eap.eap_methods == NULL) {
@@ -272,14 +341,8 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
"(sim=%d aka=%d) - initialize PCSC", sim, aka);
- if (sim && aka)
- type = SCARD_TRY_BOTH;
- else if (aka)
- type = SCARD_USIM_ONLY;
- else
- type = SCARD_GSM_SIM_ONLY;
- wpa_s->scard = scard_init(type);
+ wpa_s->scard = scard_init(NULL);
if (wpa_s->scard == NULL) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
"(pcsc-lite)");
@@ -295,10 +358,24 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_SCAN_PROCESSING
-static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
+
+static int has_wep_key(struct wpa_ssid *ssid)
+{
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
struct wpa_ssid *ssid)
{
- int i, privacy = 0;
+ int privacy = 0;
if (ssid->mixed_cell)
return 1;
@@ -308,12 +385,9 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
return 1;
#endif /* CONFIG_WPS */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i]) {
- privacy = 1;
- break;
- }
- }
+ if (has_wep_key(ssid))
+ privacy = 1;
+
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
@@ -332,7 +406,7 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_scan_res *bss)
+ struct wpa_bss *bss)
{
struct wpa_ie_data ie;
int proto_match = 0;
@@ -350,7 +424,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
- rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
proto_match++;
@@ -394,7 +468,9 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) ==
+ MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
"frame protection");
break;
@@ -405,7 +481,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
return 1;
}
- wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
proto_match++;
@@ -451,6 +527,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
return 1;
}
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
+ !rsn_ie) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X");
+ return 1;
+ }
+
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
@@ -501,7 +583,25 @@ static int ht_supported(const struct hostapd_hw_modes *mode)
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
+static int vht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports VHT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
+ * TODO: Verify if this complies with the standard
+ */
+ return (mode->vht_mcs_set[0] & 0x3) != 3;
+}
+
+
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -539,7 +639,7 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
return 0;
for (i = 0; i < (int) sizeof(scan_ie); i++) {
- rate_ie = wpa_scan_get_ie(bss, scan_ie[i]);
+ rate_ie = wpa_bss_get_ie(bss, scan_ie[i]);
if (rate_ie == NULL)
continue;
@@ -566,6 +666,18 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
continue;
}
+ /* There's also a VHT selector for 802.11ac */
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) {
+ if (!vht_supported(mode)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support "
+ "VHT PHY");
+ return 0;
+ }
+ continue;
+ }
+
if (!flagged)
continue;
@@ -592,37 +704,57 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
}
+static int bss_is_dmg(struct wpa_bss *bss)
+{
+ return bss->freq > 45000;
+}
+
+
+/*
+ * Test whether BSS is in an ESS.
+ * This is done differently in DMG (60 GHz) and non-DMG bands
+ */
+static int bss_is_ess(struct wpa_bss *bss)
+{
+ if (bss_is_dmg(bss)) {
+ return (bss->caps & IEEE80211_CAP_DMG_MASK) ==
+ IEEE80211_CAP_DMG_AP;
+ }
+
+ return ((bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+ IEEE80211_CAP_ESS);
+}
+
+
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
- int i, struct wpa_scan_res *bss,
+ int i, struct wpa_bss *bss,
struct wpa_ssid *group)
{
- const u8 *ssid_;
- u8 wpa_ie_len, rsn_ie_len, ssid_len;
+ u8 wpa_ie_len, rsn_ie_len;
int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
- ssid_ = ie ? ie + 2 : (u8 *) "";
- ssid_len = ie ? ie[1] : 0;
-
- ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
- ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
- "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s",
- i, MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len),
+ "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s%s",
+ i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
- wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+ wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
+ (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
+ " p2p" : "");
e = wpa_blacklist_get(wpa_s, bss->bssid);
if (e) {
int limit = 1;
- if (wpa_supplicant_enabled_networks(wpa_s->conf) == 1) {
+ if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
/*
* When only a single network is enabled, we can
* trigger blacklisting on the first failure. This
@@ -640,21 +772,39 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
}
}
- if (ssid_len == 0) {
+ if (bss->ssid_len == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
return NULL;
}
+ if (disallowed_bssid(wpa_s, bss->bssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
+ return NULL;
+ }
+
+ if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
+ return NULL;
+ }
+
wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
+ int res;
- if (ssid->disabled) {
+ if (wpas_network_disabled(wpa_s, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
+ "temporarily for %d second(s)", res);
+ continue;
+ }
+
#ifdef CONFIG_WPS
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
@@ -682,8 +832,8 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
check_ssid = 0;
if (check_ssid &&
- (ssid_len != ssid->ssid_len ||
- os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
+ (bss->ssid_len != ssid->ssid_len ||
+ os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
continue;
}
@@ -706,15 +856,20 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+ has_wep_key(ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block");
+ continue;
+ }
+
if (!wpa_supplicant_match_privacy(bss, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
"mismatch");
continue;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
- "network");
+ if (!bss_is_ess(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network");
continue;
}
@@ -731,6 +886,39 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ continue;
+ }
+
+ if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+ struct wpabuf *p2p_ie;
+ u8 dev_addr[ETH_ALEN];
+
+ ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (ie == NULL) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P element");
+ continue;
+ }
+ p2p_ie = wpa_bss_get_vendor_ie_multi(
+ bss, P2P_IE_VENDOR_TYPE);
+ if (p2p_ie == NULL) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - could not fetch P2P element");
+ continue;
+ }
+
+ if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
+ || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
+ ETH_ALEN) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no matching GO P2P Device Address in P2P element");
+ wpabuf_free(p2p_ie);
+ continue;
+ }
+ wpabuf_free(p2p_ie);
+ }
+
/*
* TODO: skip the AP if its P2P IE has Group Formation
* bit set in the P2P Group Capability Bitmap and we
@@ -749,56 +937,51 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
static struct wpa_bss *
wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res,
struct wpa_ssid *group,
struct wpa_ssid **selected_ssid)
{
- size_t i;
+ unsigned int i;
wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
group->priority);
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- const u8 *ie, *ssid;
- u8 ssid_len;
-
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group);
if (!*selected_ssid)
continue;
-
- ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
- ssid = ie ? ie + 2 : (u8 *) "";
- ssid_len = ie ? ie[1] : 0;
-
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
" ssid='%s'",
- MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
- return wpa_bss_get(wpa_s, bss->bssid, ssid, ssid_len);
+ MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ return bss;
}
return NULL;
}
-static struct wpa_bss *
-wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res,
- struct wpa_ssid **selected_ssid)
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
int prio;
+ if (wpa_s->last_scan_res == NULL ||
+ wpa_s->last_scan_res_used == 0)
+ return NULL; /* no scan results from last update */
+
while (selected == NULL) {
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
selected = wpa_supplicant_select_bss(
- wpa_s, scan_res, wpa_s->conf->pssid[prio],
+ wpa_s, wpa_s->conf->pssid[prio],
selected_ssid);
if (selected)
break;
}
- if (selected == NULL && wpa_s->blacklist) {
+ if (selected == NULL && wpa_s->blacklist &&
+ !wpa_s->countermeasures) {
wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
"blacklist and try again");
wpa_blacklist_clear(wpa_s);
@@ -814,15 +997,19 @@ wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
int timeout_sec, int timeout_usec)
{
- if (!wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ if (!wpa_supplicant_enabled_networks(wpa_s)) {
/*
* No networks are enabled; short-circuit request so
* we don't wait timeout seconds before transitioning
* to INACTIVE state.
*/
+ wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request "
+ "since there are no enabled networks");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
return;
}
+
+ wpa_s->scan_for_connection = 1;
wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
}
@@ -845,6 +1032,15 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
return -1;
}
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Considering connect request: reassociate: %d selected: "
+ MACSTR " bssid: " MACSTR " pending: " MACSTR
+ " wpa_state: %s ssid=%p current_ssid=%p",
+ wpa_s->reassociate, MAC2STR(selected->bssid),
+ MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ ssid, wpa_s->current_ssid);
+
/*
* Do not trigger new association unless the BSSID has changed or if
* reassociation is requested. If we are in process of associating with
@@ -854,22 +1050,21 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
(os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
((wpa_s->wpa_state != WPA_ASSOCIATING &&
wpa_s->wpa_state != WPA_AUTHENTICATING) ||
- os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
- 0))) {
+ (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+ 0) ||
+ (is_zero_ether_addr(wpa_s->pending_bssid) &&
+ ssid != wpa_s->current_ssid)))) {
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
wpa_supplicant_req_new_scan(wpa_s, 10, 0);
return 0;
}
- wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
- "reassociate: %d selected: "MACSTR " bssid: " MACSTR
- " pending: " MACSTR " wpa_state: %s",
- wpa_s->reassociate, MAC2STR(selected->bssid),
- MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
- wpa_supplicant_state_txt(wpa_s->wpa_state));
+ wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
+ MAC2STR(selected->bssid));
wpa_supplicant_associate(wpa_s, selected, ssid);
} else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
- "selected AP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
+ "connect with the selected AP");
}
return 0;
@@ -885,7 +1080,7 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
{
- if (ssid->disabled)
+ if (wpas_network_disabled(wpa_s, ssid))
continue;
if (ssid->mode == IEEE80211_MODE_IBSS ||
ssid->mode == IEEE80211_MODE_AP)
@@ -925,11 +1120,9 @@ static void wpa_supplicant_rsn_preauth_scan_results(
static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected,
- struct wpa_ssid *ssid,
- struct wpa_scan_results *scan_res)
+ struct wpa_ssid *ssid)
{
- size_t i;
- struct wpa_scan_res *current_bss = NULL;
+ struct wpa_bss *current_bss = NULL;
int min_diff;
if (wpa_s->reassociate)
@@ -944,25 +1137,23 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
if (wpas_driver_bss_selection(wpa_s))
return 0; /* Driver-based roaming */
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *res = scan_res->res[i];
- const u8 *ie;
- if (os_memcmp(res->bssid, wpa_s->bssid, ETH_ALEN) != 0)
- continue;
-
- ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
- if (ie == NULL)
- continue;
- if (ie[1] != wpa_s->current_ssid->ssid_len ||
- os_memcmp(ie + 2, wpa_s->current_ssid->ssid, ie[1]) != 0)
- continue;
- current_bss = res;
- break;
- }
+ if (wpa_s->current_ssid->ssid)
+ current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len);
+ if (!current_bss)
+ current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
if (!current_bss)
return 1; /* current BSS not seen in scan results */
+ if (current_bss == selected)
+ return 0;
+
+ if (selected->last_update_idx > current_bss->last_update_idx)
+ return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
MAC2STR(current_bss->bssid), current_bss->level);
@@ -977,6 +1168,12 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
+ if (current_bss->level < 0 && current_bss->level > selected->level) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
+ "signal level");
+ return 0;
+ }
+
min_diff = 2;
if (current_bss->level < 0) {
if (current_bss->level < -85)
@@ -997,16 +1194,24 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
}
return 1;
+#else /* CONFIG_NO_ROAMING */
+ return 0;
+#endif /* CONFIG_NO_ROAMING */
}
-/* Return < 0 if no scan results could be fetched. */
+
+/* Return != 0 if no scan results could be fetched or if scan results should not
+ * be shared with other virtual interfaces. */
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+ union wpa_event_data *data,
+ int own_request)
{
- struct wpa_bss *selected;
- struct wpa_ssid *ssid = NULL;
- struct wpa_scan_results *scan_res;
+ struct wpa_scan_results *scan_res = NULL;
+ int ret = 0;
int ap = 0;
+#ifndef CONFIG_NO_RANDOM_POOL
+ size_t i, num;
+#endif /* CONFIG_NO_RANDOM_POOL */
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
@@ -1015,32 +1220,23 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpa_supplicant_notify_scanning(wpa_s, 0);
-#ifdef CONFIG_P2P
- if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "stopped scan processing");
- return -1;
- }
- }
-#endif /* CONFIG_P2P */
-
scan_res = wpa_supplicant_get_scan_results(wpa_s,
data ? &data->scan_info :
NULL, 1);
if (scan_res == NULL) {
- if (wpa_s->conf->ap_scan == 2 || ap)
+ if (wpa_s->conf->ap_scan == 2 || ap ||
+ wpa_s->scan_res_handler == scan_only_handler)
+ return -1;
+ if (!own_request)
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);
- return -1;
+ ret = -1;
+ goto scan_work_done;
}
#ifndef CONFIG_NO_RANDOM_POOL
- size_t i, num;
num = scan_res->num;
if (num > 10)
num = 10;
@@ -1056,16 +1252,16 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_NO_RANDOM_POOL */
- if (wpa_s->scan_res_handler) {
+ if (own_request && wpa_s->scan_res_handler &&
+ (wpa_s->own_scan_running || !wpa_s->external_scan_running)) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
scan_res_handler = wpa_s->scan_res_handler;
wpa_s->scan_res_handler = NULL;
scan_res_handler(wpa_s, scan_res);
-
- wpa_scan_results_free(scan_res);
- return 0;
+ ret = -2;
+ goto scan_work_done;
}
if (ap) {
@@ -1074,42 +1270,84 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
if (wpa_s->ap_iface->scan_cb)
wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
#endif /* CONFIG_AP */
- wpa_scan_results_free(scan_res);
- return 0;
+ goto scan_work_done;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
- wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
+ wpa_s->own_scan_running, wpa_s->external_scan_running);
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+ 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;
+ } else {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ }
wpas_notify_scan_results(wpa_s);
wpas_notify_scan_done(wpa_s, 1);
- if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
+ if (!wpa_s->own_scan_running && wpa_s->external_scan_running) {
+ 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;
}
+ if (sme_proc_obss_scan(wpa_s) > 0)
+ goto scan_work_done;
+
+ if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
+ goto scan_work_done;
+
+ if (autoscan_notify_scan(wpa_s, scan_res))
+ goto scan_work_done;
+
if (wpa_s->disconnected) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
- wpa_scan_results_free(scan_res);
- return 0;
+ goto scan_work_done;
}
if (!wpas_driver_bss_selection(wpa_s) &&
- bgscan_notify_scan(wpa_s, scan_res) == 1) {
- wpa_scan_results_free(scan_res);
- return 0;
+ bgscan_notify_scan(wpa_s, scan_res) == 1)
+ goto scan_work_done;
+
+ wpas_wps_update_ap_info(wpa_s, scan_res);
+
+ wpa_scan_results_free(scan_res);
+
+ if (wpa_s->scan_work) {
+ struct wpa_radio_work *work = wpa_s->scan_work;
+ wpa_s->scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
+
+scan_work_done:
+ wpa_scan_results_free(scan_res);
+ if (wpa_s->scan_work) {
+ struct wpa_radio_work *work = wpa_s->scan_work;
+ wpa_s->scan_work = NULL;
+ radio_work_done(work);
}
+ return ret;
+}
+
+
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+ int new_scan, int own_request)
+{
+ struct wpa_bss *selected;
+ struct wpa_ssid *ssid = NULL;
- selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
+ selected = wpa_supplicant_pick_network(wpa_s, &ssid);
if (selected) {
int skip;
- skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
- scan_res);
- wpa_scan_results_free(scan_res);
+ skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
if (skip) {
- wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+ if (new_scan)
+ wpa_supplicant_rsn_preauth_scan_results(wpa_s);
return 0;
}
@@ -1117,23 +1355,39 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
return -1;
}
- wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+ if (new_scan)
+ wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+ /*
+ * Do not notify other virtual radios of scan results since we do not
+ * want them to start other associations at the same time.
+ */
+ return 1;
} else {
- wpa_scan_results_free(scan_res);
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
wpa_supplicant_associate(wpa_s, NULL, ssid);
- wpa_supplicant_rsn_preauth_scan_results(wpa_s);
- } else {
+ if (new_scan)
+ wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+ } else if (own_request) {
+ /*
+ * No SSID found. If SCAN results are as a result of
+ * own scan request and not due to a scan request on
+ * another shared interface, try another scan.
+ */
int timeout_sec = wpa_s->scan_interval;
int timeout_usec = 0;
#ifdef CONFIG_P2P
- if (wpa_s->p2p_in_provisioning) {
+ if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+ return 0;
+
+ if (wpa_s->p2p_in_provisioning ||
+ wpa_s->show_group_started) {
/*
* Use shorter wait during P2P Provisioning
- * state to speed up group formation.
+ * state and during P2P join-a-group operation
+ * to speed up group formation.
*/
timeout_sec = 0;
timeout_usec = 250000;
@@ -1142,6 +1396,29 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return 0;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->auto_interworking &&
+ wpa_s->conf->interworking &&
+ wpa_s->conf->cred) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: "
+ "start ANQP fetch since no matching "
+ "networks found");
+ wpa_s->network_select = 1;
+ wpa_s->auto_network_select = 1;
+ interworking_start_fetch_anqp(wpa_s);
+ return 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_WPS
+ if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing");
+ timeout_sec = 0;
+ timeout_usec = 500000;
+ wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+ timeout_usec);
+ return 0;
+ }
+#endif /* CONFIG_WPS */
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
timeout_usec);
@@ -1154,46 +1431,171 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- const char *rn, *rn2;
struct wpa_supplicant *ifs;
- if (_wpa_supplicant_event_scan_results(wpa_s, data) < 0) {
+ if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
/*
* If no scan results could be fetched, then no need to
* notify those interfaces that did not actually request
- * this scan.
+ * this scan. Similarly, if scan results started a new operation on this
+ * interface, do not notify other interfaces to avoid concurrent
+ * operations during a connection attempt.
*/
return;
}
/*
- * Check other interfaces to see if they have the same radio-name. If
+ * Check other interfaces to see if they share the same radio. If
* so, they get updated with this same scan info.
*/
- if (!wpa_s->driver->get_radio_name)
- return;
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s) {
+ wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
+ "sibling", ifs->ifname);
+ _wpa_supplicant_event_scan_results(ifs, data, 0);
+ }
+ }
+}
+
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- if (rn == NULL || rn[0] == '\0')
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ struct os_reltime now;
+
+ if (wpa_s->last_scan_res_used <= 0)
+ return -1;
+
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
+ wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
+ return -1;
+ }
+
+ return wpas_select_network_from_last_scan(wpa_s, 0, 1);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
+#ifdef CONFIG_WNM
+
+static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
return;
- wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
- "sharing same radio (%s) in event_scan_results", rn);
+ if (!wpa_s->no_keep_alive) {
+ wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
+ MAC2STR(wpa_s->bssid));
+ /* TODO: could skip this if normal data traffic has been sent */
+ /* TODO: Consider using some more appropriate data frame for
+ * this */
+ if (wpa_s->l2)
+ l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800,
+ (u8 *) "", 0);
+ }
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
- continue;
+#ifdef CONFIG_SME
+ if (wpa_s->sme.bss_max_idle_period) {
+ unsigned int msec;
+ msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */
+ if (msec > 100)
+ msec -= 100;
+ eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+ wnm_bss_keep_alive, wpa_s, NULL);
+ }
+#endif /* CONFIG_SME */
+}
- rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
- if (rn2 && os_strcmp(rn, rn2) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
- "sibling", ifs->ifname);
- _wpa_supplicant_event_scan_results(ifs, data);
+
+static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ies == NULL)
+ return;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+#ifdef CONFIG_SME
+ if (elems.bss_max_idle_period) {
+ unsigned int msec;
+ wpa_s->sme.bss_max_idle_period =
+ WPA_GET_LE16(elems.bss_max_idle_period);
+ wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 "
+ "TU)%s", wpa_s->sme.bss_max_idle_period,
+ (elems.bss_max_idle_period[2] & 0x01) ?
+ " (protected keep-live required)" : "");
+ if (wpa_s->sme.bss_max_idle_period == 0)
+ wpa_s->sme.bss_max_idle_period = 1;
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+ /* msec times 1000 */
+ msec = wpa_s->sme.bss_max_idle_period * 1024;
+ if (msec > 100)
+ msec -= 100;
+ eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+ wnm_bss_keep_alive, wpa_s,
+ NULL);
}
}
+#endif /* CONFIG_SME */
}
-#endif /* CONFIG_NO_SCAN_PROCESSING */
+#endif /* CONFIG_WNM */
+
+
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+#endif /* CONFIG_WNM */
+}
+
+
+#ifdef CONFIG_INTERWORKING
+
+static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+ size_t len)
+{
+ int res;
+
+ wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len);
+ res = wpa_drv_set_qos_map(wpa_s, qos_map, len);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver");
+ }
+
+ return res;
+}
+
+
+static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ies == NULL)
+ return;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+ if (elems.qos_map_set) {
+ wpas_qos_map_set(wpa_s, elems.qos_map_set,
+ elems.qos_map_set_len);
+ }
+}
+
+#endif /* CONFIG_INTERWORKING */
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
@@ -1201,6 +1603,9 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
{
int l, len, found = 0, wpa_found, rsn_found;
const u8 *p;
+#ifdef CONFIG_IEEE80211R
+ u8 bssid[ETH_ALEN];
+#endif /* CONFIG_IEEE80211R */
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies)
@@ -1213,6 +1618,14 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+ wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+#endif /* CONFIG_INTERWORKING */
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -1251,7 +1664,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- u8 bssid[ETH_ALEN];
if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
@@ -1309,6 +1721,23 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SME */
+ /* Process FT when SME is in the driver */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_ft_is_completed(wpa_s->wpa)) {
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ wpa_ft_validate_reassoc_resp(wpa_s->wpa,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
+ "Reassociation Response failed");
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_INVALID_IE);
+ return -1;
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done");
+ }
+
wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
@@ -1365,13 +1794,35 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
+static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
+{
+ const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+
+ if (!wpa_s->current_bss || !wpa_s->current_ssid)
+ return -1;
+
+ if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt))
+ return 0;
+
+ bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+ WPA_IE_VENDOR_TYPE);
+ bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+
+ if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+ bss_wpa ? 2 + bss_wpa[1] : 0) ||
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+ bss_rsn ? 2 + bss_rsn[1] : 0))
+ return -1;
+
+ return 0;
+}
+
+
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
u8 bssid[ETH_ALEN];
int ft_completed;
- int bssid_changed;
- struct wpa_driver_capa capa;
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -1388,36 +1839,36 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
- if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
- os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
random_add_randomness(bssid, ETH_ALEN);
- bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN);
os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
+ wpas_notify_bssid_changed(wpa_s);
if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
wpa_clear_keys(wpa_s, bssid);
}
if (wpa_supplicant_select_config(wpa_s) < 0) {
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
return;
}
- if (wpa_s->current_ssid) {
- struct wpa_bss *bss = NULL;
- struct wpa_ssid *ssid = wpa_s->current_ssid;
- if (ssid->ssid_len > 0)
- bss = wpa_bss_get(wpa_s, bssid,
- ssid->ssid, ssid->ssid_len);
- if (!bss)
- bss = wpa_bss_get_bssid(wpa_s, bssid);
- if (bss)
- wpa_s->current_bss = bss;
+
+ if (wpa_s->conf->ap_scan == 1 &&
+ wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
+ if (wpa_supplicant_assoc_update_ie(wpa_s) < 0)
+ wpa_msg(wpa_s, MSG_WARNING,
+ "WPA/RSN IEs not updated");
}
}
@@ -1459,6 +1910,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
(wpa_s->current_ssid &&
wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
+ /*
+ * Set the key after having received joined-IBSS event
+ * from the driver.
+ */
+ wpa_supplicant_set_wpa_none_key(wpa_s,
+ wpa_s->current_ssid);
+ }
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else if (!ft_completed) {
@@ -1496,10 +1957,12 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
}
+ wpa_s->last_eapol_matches_bssid = 0;
+
if (wpa_s->pending_eapol_rx) {
- struct os_time now, age;
- os_get_time(&now);
- os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
+ struct os_reltime now, age;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
if (age.sec == 0 && age.usec < 100000 &&
os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
0) {
@@ -1517,8 +1980,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
- wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
- capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
+ wpa_s->current_ssid &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
}
@@ -1540,15 +2003,82 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
}
#endif /* CONFIG_IBSS_RSN */
+
+ wpas_wps_notify_assoc(wpa_s, bssid);
+}
+
+
+static int disconnect_reason_recoverable(u16 reason_code)
+{
+ return reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY ||
+ reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ||
+ reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
}
static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
- u16 reason_code)
+ u16 reason_code,
+ int locally_generated)
+{
+ const u8 *bssid;
+
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+ /*
+ * At least Host AP driver and a Prism3 card seemed to be
+ * generating streams of disconnected events when configuring
+ * IBSS for WPA-None. Ignore them for now.
+ */
+ return;
+ }
+
+ bssid = wpa_s->bssid;
+ if (is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+
+ if (!is_zero_ether_addr(bssid) ||
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+ " reason=%d%s",
+ MAC2STR(bssid), reason_code,
+ locally_generated ? " locally_generated=1" : "");
+ }
+}
+
+
+static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
+ int locally_generated)
+{
+ if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+ return 0; /* Not in 4-way handshake with PSK */
+
+ /*
+ * It looks like connection was lost while trying to go through PSK
+ * 4-way handshake. Filter out known disconnection cases that are caused
+ * by something else than PSK mismatch to avoid confusing reports.
+ */
+
+ if (locally_generated) {
+ if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
+ u16 reason_code,
+ int locally_generated)
{
const u8 *bssid;
int authenticating;
u8 prev_pending_bssid[ETH_ALEN];
+ struct wpa_bss *fast_reconnect = NULL;
+#ifndef CONFIG_NO_SCAN_PROCESSING
+ struct wpa_ssid *fast_reconnect_ssid = NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+ struct wpa_ssid *last_ssid;
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -1564,20 +2094,42 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
return;
}
- if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
- wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ 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");
- }
- if (!wpa_s->auto_reconnect_disabled ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Auto connect enabled: try to "
- "reconnect (wps=%d)",
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
- if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+ if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
+ return; /* P2P group removed */
+ wpas_auth_failed(wpa_s);
+ }
+ if (!wpa_s->disconnected &&
+ (!wpa_s->auto_reconnect_disabled ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
+ "reconnect (wps=%d wpa_state=%d)",
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+ wpa_s->wpa_state);
+ if (wpa_s->wpa_state == WPA_COMPLETED &&
+ wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+ !locally_generated &&
+ disconnect_reason_recoverable(reason_code)) {
+ /*
+ * It looks like the AP has dropped association with
+ * us, but could allow us to get back in. Try to
+ * reconnect to the same BSS without full scan to save
+ * time for some common cases.
+ */
+ fast_reconnect = wpa_s->current_bss;
+#ifndef CONFIG_NO_SCAN_PROCESSING
+ fast_reconnect_ssid = wpa_s->current_ssid;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+ } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
wpa_supplicant_req_scan(wpa_s, 0, 100000);
+ else
+ wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
+ "immediate scan");
} else {
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Auto connect disabled: do not "
+ wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
"try to re-connect");
wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
@@ -1586,20 +2138,36 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
bssid = wpa_s->bssid;
if (is_zero_ether_addr(bssid))
bssid = wpa_s->pending_bssid;
- wpas_connection_failed(wpa_s, bssid);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpas_connection_failed(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
- " reason=%d",
- MAC2STR(bssid), reason_code);
+ if (locally_generated)
+ wpa_s->disconnect_reason = -reason_code;
+ else
+ wpa_s->disconnect_reason = reason_code;
+ wpas_notify_disconnect_reason(wpa_s);
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
- wpa_s->keys_cleared = 0;
wpa_clear_keys(wpa_s, wpa_s->bssid);
}
+ last_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
- if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ 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;
+ }
+
+ if (fast_reconnect) {
+#ifndef CONFIG_NO_SCAN_PROCESSING
+ wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
+ if (wpa_supplicant_connect(wpa_s, fast_reconnect,
+ fast_reconnect_ssid) < 0) {
+ /* Recover through full scan */
+ wpa_supplicant_req_scan(wpa_s, 0, 100000);
+ }
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+ }
}
@@ -1623,13 +2191,13 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
int pairwise;
- struct os_time t;
+ struct os_reltime t;
wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
pairwise = (data && data->michael_mic_failure.unicast);
- os_get_time(&t);
- if ((wpa_s->last_michael_mic_error &&
- t.sec - wpa_s->last_michael_mic_error <= 60) ||
+ os_get_reltime(&t);
+ if ((wpa_s->last_michael_mic_error.sec &&
+ !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) ||
wpa_s->pending_mic_error_report) {
if (wpa_s->pending_mic_error_report) {
/*
@@ -1648,6 +2216,9 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
/* initialize countermeasures */
wpa_s->countermeasures = 1;
+
+ wpa_blacklist_add(wpa_s, wpa_s->bssid);
+
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
/*
@@ -1704,7 +2275,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
}
- wpa_s->last_michael_mic_error = t.sec;
+ wpa_s->last_michael_mic_error = t;
wpa_s->mic_errors_seen++;
}
@@ -1739,7 +2310,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
"driver after interface was added");
}
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
break;
case EVENT_INTERFACE_REMOVED:
wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
@@ -1782,17 +2352,44 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
return;
switch (data->tdls.oper) {
case TDLS_REQUEST_SETUP:
- wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+ wpa_tdls_remove(wpa_s->wpa, data->tdls.peer);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+ else
+ wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
break;
case TDLS_REQUEST_TEARDOWN:
- wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
- data->tdls.reason_code);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
+ data->tdls.reason_code);
+ else
+ wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN,
+ data->tdls.peer);
break;
}
}
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (data == NULL)
+ return;
+ switch (data->wnm.oper) {
+ case WNM_OPER_SLEEP:
+ wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request "
+ "(action=%d, intval=%d)",
+ data->wnm.sleep_action, data->wnm.sleep_intval);
+ ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action,
+ data->wnm.sleep_intval, NULL);
+ break;
+ }
+}
+#endif /* CONFIG_WNM */
+
+
#ifdef CONFIG_IEEE80211R
static void
wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
@@ -1830,6 +2427,23 @@ static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
}
+
+
+static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid == NULL)
+ return;
+
+ /* check if the ssid is correctly configured as IBSS/RSN */
+ if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+ return;
+
+ ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame,
+ data->rx_mgmt.frame_len);
+}
#endif /* CONFIG_IBSS_RSN */
@@ -1913,67 +2527,338 @@ static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
}
-static void wnm_action_rx(struct wpa_supplicant *wpa_s, struct rx_action *rx)
+static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr,
+ u16 reason_code, int locally_generated,
+ const u8 *ie, size_t ie_len, int deauth)
+{
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && addr) {
+ hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], addr);
+ return;
+ }
+
+ if (wpa_s->ap_iface) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in AP mode");
+ return;
+ }
+#endif /* CONFIG_AP */
+
+ wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
+
+ if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+ ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+ (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+ eapol_sm_failed(wpa_s->eapol))) &&
+ !wpa_s->eap_expected_failure))
+ wpas_auth_failed(wpa_s);
+
+#ifdef CONFIG_P2P
+ if (deauth && reason_code > 0) {
+ if (wpas_p2p_deauth_notif(wpa_s, addr, reason_code, ie, ie_len,
+ locally_generated) > 0) {
+ /*
+ * The interface was removed, so cannot continue
+ * processing any additional operations after this.
+ */
+ return;
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
+ locally_generated);
+}
+
+
+static void wpas_event_disassoc(struct wpa_supplicant *wpa_s,
+ struct disassoc_info *info)
{
- u8 action, mode;
- const u8 *pos, *end;
+ u16 reason_code = 0;
+ int locally_generated = 0;
+ const u8 *addr = NULL;
+ const u8 *ie = NULL;
+ size_t ie_len = 0;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
+
+ if (info) {
+ addr = info->addr;
+ ie = info->ie;
+ ie_len = info->ie_len;
+ reason_code = info->reason_code;
+ locally_generated = info->locally_generated;
+ wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code,
+ locally_generated ? " (locally generated)" : "");
+ if (addr)
+ wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+ MAC2STR(addr));
+ wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
+ ie, ie_len);
+ }
- if (rx->data == NULL || rx->len == 0)
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && info && info->addr) {
+ hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], info->addr);
return;
+ }
- pos = rx->data;
- end = pos + rx->len;
- action = *pos++;
+ if (wpa_s->ap_iface) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in AP mode");
+ return;
+ }
+#endif /* CONFIG_AP */
- wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
- action, MAC2STR(rx->sa));
- switch (action) {
- case WNM_BSS_TRANS_MGMT_REQ:
- if (pos + 5 > end)
- break;
- wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
- "Request: dialog_token=%u request_mode=0x%x "
- "disassoc_timer=%u validity_interval=%u",
- pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
- mode = pos[1];
- pos += 5;
- if (mode & 0x08)
- pos += 12; /* BSS Termination Duration */
- if (mode & 0x10) {
- char url[256];
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
- wpa_printf(MSG_DEBUG, "WNM: Invalid BSS "
- "Transition Management Request "
- "(URL)");
- break;
- }
- os_memcpy(url, pos + 1, pos[0]);
- url[pos[0]] = '\0';
- wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation "
- "Imminent - session_info_url=%s", url);
+#ifdef CONFIG_P2P
+ if (info) {
+ wpas_p2p_disassoc_notif(
+ wpa_s, info->addr, reason_code, info->ie, info->ie_len,
+ locally_generated);
+ }
+#endif /* CONFIG_P2P */
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ sme_event_disassoc(wpa_s, info);
+
+ wpas_event_disconnect(wpa_s, addr, reason_code, locally_generated,
+ ie, ie_len, 0);
+}
+
+
+static void wpas_event_deauth(struct wpa_supplicant *wpa_s,
+ struct deauth_info *info)
+{
+ u16 reason_code = 0;
+ int locally_generated = 0;
+ const u8 *addr = NULL;
+ const u8 *ie = NULL;
+ size_t ie_len = 0;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Deauthentication notification");
+
+ if (info) {
+ addr = info->addr;
+ ie = info->ie;
+ ie_len = info->ie_len;
+ reason_code = info->reason_code;
+ locally_generated = info->locally_generated;
+ wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+ reason_code,
+ locally_generated ? " (locally generated)" : "");
+ if (addr) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+ MAC2STR(addr));
+ }
+ wpa_hexdump(MSG_DEBUG, "Deauthentication frame IE(s)",
+ ie, ie_len);
+ }
+
+ wpa_reset_ft_completed(wpa_s->wpa);
+
+ wpas_event_disconnect(wpa_s, addr, reason_code,
+ locally_generated, ie, ie_len, 1);
+}
+
+
+static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *ifs;
+
+ if (wpa_s->drv_priv == NULL)
+ return; /* Ignore event during drv initialization */
+
+ free_hw_features(wpa_s);
+ wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+ wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+#ifdef CONFIG_P2P
+ wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+
+ /*
+ * Check other interfaces to see if they share the same radio. If
+ * so, they get updated with this same hw mode info.
+ */
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s) {
+ wpa_printf(MSG_DEBUG, "%s: Updating hw mode",
+ ifs->ifname);
+ free_hw_features(ifs);
+ ifs->hw.modes = wpa_drv_get_hw_feature_data(
+ ifs, &ifs->hw.num_modes, &ifs->hw.flags);
}
- break;
}
}
+static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq)
+{
+ const u8 *payload;
+ size_t plen;
+ u8 category;
+
+ if (len < IEEE80211_HDRLEN + 2)
+ return;
+
+ payload = &mgmt->u.action.category;
+ category = *payload++;
+ plen = (((const u8 *) mgmt) + len) - payload;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
+ " Category=%u DataLen=%d freq=%d MHz",
+ MAC2STR(mgmt->sa), category, (int) plen, freq);
+
+#ifdef CONFIG_IEEE80211R
+ if (category == WLAN_ACTION_FT) {
+ ft_rx_action(wpa_s, payload, plen);
+ return;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_SME
+ if (category == WLAN_ACTION_SA_QUERY) {
+ sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
+ return;
+ }
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_WNM
+ if (mgmt->u.action.category == WLAN_ACTION_WNM) {
+ ieee802_11_rx_wnm_action(wpa_s, mgmt, len);
+ return;
+ }
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_GAS
+ if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC ||
+ mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) &&
+ gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid,
+ mgmt->u.action.category,
+ payload, plen, freq) == 0)
+ return;
+#endif /* CONFIG_GAS */
+
+#ifdef CONFIG_TDLS
+ if (category == WLAN_ACTION_PUBLIC && plen >= 4 &&
+ payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "TDLS: Received Discovery Response from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_INTERWORKING
+ if (category == WLAN_ACTION_QOS && plen >= 1 &&
+ payload[0] == QOS_QOS_MAP_CONFIG) {
+ const u8 *pos = payload + 1;
+ size_t qlen = plen - 1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 &&
+ qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET &&
+ pos[1] <= qlen - 2 && pos[1] >= 16)
+ wpas_qos_map_set(wpa_s, pos + 2, pos[1]);
+ return;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_P2P
+ wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+ category, payload, plen, freq);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *event)
+{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *ifs;
+#endif /* CONFIG_P2P */
+ struct wpa_freq_range_list *list;
+ char *str = NULL;
+
+ list = &event->freq_range;
+
+ if (list->num)
+ str = freq_range_list_str(list);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AVOID_FREQ "ranges=%s",
+ str ? str : "");
+
+#ifdef CONFIG_P2P
+ if (freq_range_list_parse(&wpa_s->global->p2p_go_avoid_freq, str)) {
+ wpa_dbg(wpa_s, MSG_ERROR, "%s: Failed to parse freq range",
+ __func__);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Update channel list based on frequency avoid event");
+ wpas_p2p_update_channel_list(wpa_s);
+ }
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ int freq;
+ if (!ifs->current_ssid ||
+ !ifs->current_ssid->p2p_group ||
+ (ifs->current_ssid->mode != WPAS_MODE_P2P_GO &&
+ ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION))
+ continue;
+
+ freq = ifs->current_ssid->frequency;
+ if (!freq_range_list_includes(list, freq)) {
+ wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in safe range",
+ freq);
+ continue;
+ }
+
+ wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in unsafe frequency %d MHz",
+ freq);
+ /* TODO: Consider using CSA or removing the group within
+ * wpa_supplicant */
+ wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
+ }
+#endif /* CONFIG_P2P */
+
+ os_free(str);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
- u16 reason_code = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
- event != EVENT_INTERFACE_STATUS) {
+ event != EVENT_INTERFACE_STATUS &&
+ event != EVENT_SCHED_SCAN_STOPPED) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore event %s (%d) while interface is disabled",
event_to_string(event), event);
return;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Event %s (%d) received",
+#ifndef CONFIG_NO_STDOUT_DEBUG
+{
+ int level = MSG_DEBUG;
+
+ if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+ hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+ fc = le_to_host16(hdr->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+ level = MSG_EXCESSIVE;
+ }
+
+ wpa_dbg(wpa_s, level, "Event %s (%d) received",
event_to_string(event), event);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (event) {
case EVENT_AUTH:
@@ -1983,88 +2868,55 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_supplicant_event_assoc(wpa_s, data);
break;
case EVENT_DISASSOC:
- wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
- if (data) {
- wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
- data->disassoc_info.reason_code);
- if (data->disassoc_info.addr)
- wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
- MAC2STR(data->disassoc_info.addr));
- }
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
- hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
- data->disassoc_info.addr);
- break;
- }
- if (wpa_s->ap_iface) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
- "AP mode");
- break;
- }
-#endif /* CONFIG_AP */
- if (data) {
- reason_code = data->disassoc_info.reason_code;
- wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
- data->disassoc_info.ie,
- data->disassoc_info.ie_len);
-#ifdef CONFIG_P2P
- wpas_p2p_disassoc_notif(
- wpa_s, data->disassoc_info.addr, reason_code,
- data->disassoc_info.ie,
- data->disassoc_info.ie_len);
-#endif /* CONFIG_P2P */
- }
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
- sme_event_disassoc(wpa_s, data);
- /* fall through */
+ wpas_event_disassoc(wpa_s,
+ data ? &data->disassoc_info : NULL);
+ break;
case EVENT_DEAUTH:
- if (event == EVENT_DEAUTH) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Deauthentication notification");
- if (data) {
- reason_code = data->deauth_info.reason_code;
- wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
- data->deauth_info.reason_code);
- if (data->deauth_info.addr) {
- wpa_dbg(wpa_s, MSG_DEBUG, " * address "
- MACSTR,
- MAC2STR(data->deauth_info.
- addr));
- }
- wpa_hexdump(MSG_DEBUG,
- "Deauthentication frame IE(s)",
- data->deauth_info.ie,
- data->deauth_info.ie_len);
-#ifdef CONFIG_P2P
- wpas_p2p_deauth_notif(
- wpa_s, data->deauth_info.addr,
- reason_code,
- data->deauth_info.ie,
- data->deauth_info.ie_len);
-#endif /* CONFIG_P2P */
- }
- }
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface && data && data->deauth_info.addr) {
- hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
- data->deauth_info.addr);
- break;
- }
- if (wpa_s->ap_iface) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
- "AP mode");
- break;
- }
-#endif /* CONFIG_AP */
- wpa_supplicant_event_disassoc(wpa_s, reason_code);
+ wpas_event_deauth(wpa_s,
+ data ? &data->deauth_info : NULL);
break;
case EVENT_MICHAEL_MIC_FAILURE:
wpa_supplicant_event_michael_mic_failure(wpa_s, data);
break;
#ifndef CONFIG_NO_SCAN_PROCESSING
+ case EVENT_SCAN_STARTED:
+ os_get_reltime(&wpa_s->scan_start_time);
+ if (wpa_s->own_scan_requested) {
+ struct os_reltime diff;
+
+ 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",
+ diff.sec, diff.usec);
+ wpa_s->own_scan_requested = 0;
+ wpa_s->own_scan_running = 1;
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_use_id) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED "id=%u",
+ wpa_s->manual_scan_id);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
+ }
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
+ wpa_s->external_scan_running = 1;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
+ }
+ break;
case EVENT_SCAN_RESULTS:
+ if (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);
+ wpa_s->scan_start_time.sec = 0;
+ wpa_s->scan_start_time.usec = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
+ diff.sec, diff.usec);
+ }
wpa_supplicant_event_scan_results(wpa_s, data);
+ wpa_s->own_scan_running = 0;
+ wpa_s->external_scan_running = 0;
+ radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO:
@@ -2086,6 +2938,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_supplicant_event_tdls(wpa_s, data);
break;
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+ case EVENT_WNM:
+ wpa_supplicant_event_wnm(wpa_s, data);
+ break;
+#endif /* CONFIG_WNM */
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RESPONSE:
wpa_supplicant_event_ft_response(wpa_s, data);
@@ -2108,6 +2965,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->assoc_reject.status_code);
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_reject(wpa_s, data);
+ else {
+ const u8 *bssid = data->assoc_reject.bssid;
+ if (bssid == NULL || is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ }
break;
case EVENT_AUTH_TIMED_OUT:
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
@@ -2177,6 +3041,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
break;
#ifdef CONFIG_AP
+ case EVENT_EAPOL_TX_STATUS:
+ ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst,
+ data->eapol_tx_status.data,
+ data->eapol_tx_status.data_len,
+ data->eapol_tx_status.ack);
+ break;
case EVENT_DRIVER_CLIENT_POLL_OK:
ap_client_poll_ok(wpa_s, data->client_poll.addr);
break;
@@ -2186,15 +3056,36 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
- case EVENT_RX_MGMT:
+ 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");
+ break;
+ }
+
+ 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);
+ break;
+#endif /* CONFIG_AP */
+ case EVENT_RX_MGMT: {
+ u16 fc, stype;
+ const struct ieee80211_mgmt *mgmt;
+
+ mgmt = (const struct ieee80211_mgmt *)
+ data->rx_mgmt.frame;
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+#ifdef CONFIG_AP
if (wpa_s->ap_iface == NULL) {
+#endif /* CONFIG_AP */
#ifdef CONFIG_P2P
- u16 fc, stype;
- const struct ieee80211_mgmt *mgmt;
- mgmt = (const struct ieee80211_mgmt *)
- data->rx_mgmt.frame;
- fc = le_to_host16(mgmt->frame_control);
- stype = WLAN_FC_GET_STYPE(fc);
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
data->rx_mgmt.frame_len > 24) {
const u8 *src = mgmt->sa;
@@ -2202,72 +3093,50 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
size_t ie_len = data->rx_mgmt.frame_len -
(mgmt->u.probe_req.variable -
data->rx_mgmt.frame);
- wpas_p2p_probe_req_rx(wpa_s, src, mgmt->da,
- mgmt->bssid, ie, ie_len);
+ wpas_p2p_probe_req_rx(
+ wpa_s, src, mgmt->da,
+ mgmt->bssid, ie, ie_len,
+ data->rx_mgmt.ssi_signal);
break;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_IBSS_RSN
+ if (stype == WLAN_FC_STYPE_AUTH &&
+ data->rx_mgmt.frame_len >= 30) {
+ wpa_supplicant_event_ibss_auth(wpa_s, data);
+ break;
+ }
+#endif /* CONFIG_IBSS_RSN */
+
+ if (stype == WLAN_FC_STYPE_ACTION) {
+ wpas_event_rx_mgmt_action(
+ wpa_s, mgmt, data->rx_mgmt.frame_len,
+ data->rx_mgmt.freq);
+ break;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
"management frame in non-AP mode");
break;
+#ifdef CONFIG_AP
+ }
+
+ 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);
+
+ wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
+ mgmt->bssid, ie, ie_len,
+ data->rx_mgmt.ssi_signal);
}
+
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
- break;
#endif /* CONFIG_AP */
- case EVENT_RX_ACTION:
- wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
- " Category=%u DataLen=%d freq=%d MHz",
- MAC2STR(data->rx_action.sa),
- data->rx_action.category, (int) data->rx_action.len,
- data->rx_action.freq);
-#ifdef CONFIG_IEEE80211R
- if (data->rx_action.category == WLAN_ACTION_FT) {
- ft_rx_action(wpa_s, data->rx_action.data,
- data->rx_action.len);
- break;
- }
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-#ifdef CONFIG_SME
- if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
- sme_sa_query_rx(wpa_s, data->rx_action.sa,
- data->rx_action.data,
- data->rx_action.len);
- break;
- }
-#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_GAS
- if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
- gas_query_rx(wpa_s->gas, data->rx_action.da,
- data->rx_action.sa, data->rx_action.bssid,
- data->rx_action.data, data->rx_action.len,
- data->rx_action.freq) == 0)
- break;
-#endif /* CONFIG_GAS */
- if (data->rx_action.category == WLAN_ACTION_WNM) {
- wnm_action_rx(wpa_s, &data->rx_action);
- break;
- }
-#ifdef CONFIG_TDLS
- if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
- data->rx_action.len >= 4 &&
- data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
- wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
- "Response from " MACSTR,
- MAC2STR(data->rx_action.sa));
- break;
- }
-#endif /* CONFIG_TDLS */
-#ifdef CONFIG_P2P
- wpas_p2p_rx_action(wpa_s, data->rx_action.da,
- data->rx_action.sa,
- data->rx_action.bssid,
- data->rx_action.category,
- data->rx_action.data,
- data->rx_action.len, data->rx_action.freq);
-#endif /* CONFIG_P2P */
break;
+ }
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
data->rx_probe_req.ie == NULL)
@@ -2279,7 +3148,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
- data->rx_probe_req.ie_len);
+ data->rx_probe_req.ie_len,
+ data->rx_probe_req.ssi_signal);
break;
}
#endif /* CONFIG_AP */
@@ -2288,7 +3158,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
- data->rx_probe_req.ie_len);
+ data->rx_probe_req.ie_len,
+ data->rx_probe_req.ssi_signal);
#endif /* CONFIG_P2P */
break;
case EVENT_REMAIN_ON_CHANNEL:
@@ -2313,71 +3184,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s, data->remain_on_channel.freq);
#endif /* CONFIG_P2P */
break;
-#ifdef CONFIG_P2P
- case EVENT_P2P_DEV_FOUND: {
- struct p2p_peer_info peer_info;
-
- os_memset(&peer_info, 0, sizeof(peer_info));
- if (data->p2p_dev_found.dev_addr)
- os_memcpy(peer_info.p2p_device_addr,
- data->p2p_dev_found.dev_addr, ETH_ALEN);
- if (data->p2p_dev_found.pri_dev_type)
- os_memcpy(peer_info.pri_dev_type,
- data->p2p_dev_found.pri_dev_type,
- sizeof(peer_info.pri_dev_type));
- if (data->p2p_dev_found.dev_name)
- os_strlcpy(peer_info.device_name,
- data->p2p_dev_found.dev_name,
- sizeof(peer_info.device_name));
- peer_info.config_methods = data->p2p_dev_found.config_methods;
- peer_info.dev_capab = data->p2p_dev_found.dev_capab;
- peer_info.group_capab = data->p2p_dev_found.group_capab;
-
- /*
- * FIX: new_device=1 is not necessarily correct. We should
- * maintain a P2P peer database in wpa_supplicant and update
- * this information based on whether the peer is truly new.
- */
- wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
- break;
- }
- case EVENT_P2P_GO_NEG_REQ_RX:
- wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
- data->p2p_go_neg_req_rx.dev_passwd_id);
- break;
- case EVENT_P2P_GO_NEG_COMPLETED:
- wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
- break;
- case EVENT_P2P_PROV_DISC_REQUEST:
- wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
- data->p2p_prov_disc_req.config_methods,
- data->p2p_prov_disc_req.dev_addr,
- data->p2p_prov_disc_req.pri_dev_type,
- data->p2p_prov_disc_req.dev_name,
- data->p2p_prov_disc_req.supp_config_methods,
- data->p2p_prov_disc_req.dev_capab,
- data->p2p_prov_disc_req.group_capab,
- NULL, 0);
- break;
- case EVENT_P2P_PROV_DISC_RESPONSE:
- wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
- data->p2p_prov_disc_resp.config_methods);
- break;
- case EVENT_P2P_SD_REQUEST:
- wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
- data->p2p_sd_req.sa,
- data->p2p_sd_req.dialog_token,
- data->p2p_sd_req.update_indic,
- data->p2p_sd_req.tlvs,
- data->p2p_sd_req.tlvs_len);
- break;
- case EVENT_P2P_SD_RESPONSE:
- wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
- data->p2p_sd_resp.update_indic,
- data->p2p_sd_resp.tlvs,
- data->p2p_sd_resp.tlvs_len);
- break;
-#endif /* CONFIG_P2P */
case EVENT_EAPOL_RX:
wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
data->eapol_rx.data,
@@ -2410,20 +3216,25 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
case EVENT_INTERFACE_DISABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO ||
+ (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)) {
+ /*
+ * The interface was externally disabled. Remove
+ * it assuming an external entity will start a
+ * new session if needed.
+ */
+ wpas_p2p_disconnect(wpa_s);
+ break;
+ }
+#endif /* CONFIG_P2P */
+
wpa_supplicant_mark_disassoc(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
break;
case EVENT_CHANNEL_LIST_CHANGED:
- if (wpa_s->drv_priv == NULL)
- break; /* Ignore event during drv initialization */
-
- free_hw_features(wpa_s);
- wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
- wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
-
-#ifdef CONFIG_P2P
- wpas_p2p_update_channel_list(wpa_s);
-#endif /* CONFIG_P2P */
+ wpa_supplicant_update_channel_list(wpa_s);
break;
case EVENT_INTERFACE_UNAVAILABLE:
#ifdef CONFIG_P2P
@@ -2478,21 +3289,47 @@ 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;
wpa_supplicant_notify_scanning(wpa_s, 0);
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+ break;
+
/*
- * If we timed out, start a new sched scan to continue
- * searching for more SSIDs.
+ * Start a new sched scan to continue searching for more SSIDs
+ * either if timed out or PNO schedule scan is pending.
*/
- if (wpa_s->sched_scan_timed_out)
- wpa_supplicant_req_sched_scan(wpa_s);
+ if (wpa_s->sched_scan_timed_out || wpa_s->pno_sched_pending) {
+
+ if (wpa_supplicant_req_sched_scan(wpa_s) < 0 &&
+ wpa_s->pno_sched_pending) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO");
+ } else if (wpa_s->pno_sched_pending) {
+ wpa_s->pno_sched_pending = 0;
+ wpa_s->pno = 1;
+ }
+ }
+
break;
case EVENT_WPS_BUTTON_PUSHED:
#ifdef CONFIG_WPS
wpas_wps_start_pbc(wpa_s, NULL, 0);
#endif /* CONFIG_WPS */
break;
+ case EVENT_AVOID_FREQUENCIES:
+ wpa_supplicant_notify_avoid_freq(wpa_s, data);
+ break;
+ case EVENT_CONNECT_FAILED_REASON:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface || !data)
+ break;
+ hostapd_event_connect_failed_reason(
+ wpa_s->ap_iface->bss[0],
+ data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+#endif /* CONFIG_AP */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant/examples/dbus-listen-preq.py
new file mode 100644
index 0000000..5ac9859
--- /dev/null
+++ b/wpa_supplicant/examples/dbus-listen-preq.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+import time
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+
+WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
+WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
+
+def usage():
+ print "Usage: %s <ifname>" % sys.argv[0]
+ print "Press Ctrl-C to stop"
+
+def ProbeRequest(args):
+ if 'addr' in args:
+ print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ if 'dst' in args:
+ print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ if 'bssid' in args:
+ print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ if 'signal' in args:
+ print 'signal:%d' % args['signal'],
+ if 'ies' in args:
+ print 'have IEs (%d bytes)' % len(args['ies']),
+ print ''
+
+if __name__ == "__main__":
+ global bus
+ global wpas_obj
+ global if_obj
+ global p2p_iface
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
+
+ # Print list of i/f if no one is specified
+ if (len(sys.argv) < 2) :
+ usage()
+ sys.exit(0)
+
+ wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
+
+ ifname = sys.argv[1]
+
+ path = wpas.GetInterface(ifname)
+
+ if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+ iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
+
+ bus.add_signal_receiver(ProbeRequest,
+ dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+ signal_name="ProbeRequest")
+
+ iface.SubscribeProbeReq()
+
+ gobject.MainLoop().run()
diff --git a/wpa_supplicant/examples/p2p-action.sh b/wpa_supplicant/examples/p2p-action.sh
index 8759f54..797d43a 100755
--- a/wpa_supplicant/examples/p2p-action.sh
+++ b/wpa_supplicant/examples/p2p-action.sh
@@ -34,13 +34,26 @@ if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
# start with -z to avoid that
dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
-i $GIFNAME \
- -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z
+ -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z -p 0
fi
fi
if [ "$4" = "client" ]; then
kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
rm /var/run/dhclient.leases-$GIFNAME
kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+ ipaddr=`echo "$*" | sed 's/.* ip_addr=\([^ ]*\).*/\1/'`
+ ipmask=`echo "$*" | sed 's/.* ip_mask=\([^ ]*\).*/\1/'`
+ goipaddr=`echo "$*" | sed 's/.* go_ip_addr=\([^ ]*\).*/\1/'`
+ if echo "$ipaddr$ipmask$goipaddr" | grep -q ' '; then
+ ipaddr=""
+ ipmask=""
+ goipaddr=""
+ fi
+ if [ -n "$ipaddr" ]; then
+ sudo ifconfig $GIFNAME "$ipaddr" netmask "$ipmask"
+ sudo ip ro re default via "$goipaddr"
+ exit 0
+ fi
dhclient -pf /var/run/dhclient-$GIFNAME.pid \
-lf /var/run/dhclient.leases-$GIFNAME \
-nw \
diff --git a/wpa_supplicant/examples/p2p-nfc.py b/wpa_supplicant/examples/p2p-nfc.py
new file mode 100644
index 0000000..848f79f
--- /dev/null
+++ b/wpa_supplicant/examples/p2p-nfc.py
@@ -0,0 +1,581 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import random
+import threading
+import argparse
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+include_wps_req = True
+include_p2p_req = True
+no_input = False
+srv = None
+continue_loop = True
+terminate_now = False
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find wpa_supplicant: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No wpa_supplicant control interface found"
+ return None
+
+ for ctrl in ifaces:
+ if ifname:
+ if ifname not in ctrl:
+ continue
+ try:
+ print "Trying to use control interface " + ctrl
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return
+ cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex")
+ global force_freq
+ if force_freq:
+ cmd = cmd + " freq=" + force_freq
+ if "FAIL" in wpas.request(cmd):
+ return False
+ return True
+
+
+def wpas_get_handover_req():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip().decode("hex")
+ if "FAIL" in res:
+ return None
+ return res
+
+def wpas_get_handover_req_wps():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel(tag=False):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if tag:
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip().decode("hex")
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel_wps():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR");
+ if "FAIL" in res:
+ return None
+ return res.rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex")
+ global force_freq
+ if force_freq:
+ cmd = cmd + " freq=" + force_freq
+ return wpas.request(cmd)
+
+
+def wpas_report_handover_wsc(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex")
+ if force_freq:
+ cmd = cmd + " freq=" + force_freq
+ return wpas.request(cmd)
+
+
+def p2p_handover_client(llc):
+ message = nfc.ndef.HandoverRequestMessage(version="1.2")
+ message.nonce = random.randint(0, 0xffff)
+
+ global include_p2p_req
+ if include_p2p_req:
+ data = wpas_get_handover_req()
+ if (data == None):
+ print "Could not get handover request carrier record from wpa_supplicant"
+ return
+ print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ datamsg = nfc.ndef.Message(data)
+ message.add_carrier(datamsg[0], "active", datamsg[1:])
+
+ global include_wps_req
+ if include_wps_req:
+ print "Handover request (pre-WPS):"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+
+ data = wpas_get_handover_req_wps()
+ if data:
+ print "Add WPS request in addition to P2P"
+ datamsg = nfc.ndef.Message(data)
+ message.add_carrier(datamsg[0], "active", datamsg[1:])
+
+ print "Handover request:"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+ print str(message).encode("hex")
+
+ client = nfc.handover.HandoverClient(llc)
+ try:
+ print "Trying handover";
+ client.connect()
+ print "Connected for handover"
+ except nfc.llcp.ConnectRefused:
+ print "Handover connection refused"
+ client.close()
+ return
+ except Exception, e:
+ print "Other exception: " + str(e)
+ client.close()
+ return
+
+ print "Sending handover request"
+
+ if not client.send(message):
+ print "Failed to send handover request"
+
+ print "Receiving handover response"
+ message = client._recv()
+ if message is None:
+ print "No response received"
+ client.close()
+ return
+ if message.type != "urn:nfc:wkt:Hs":
+ print "Response was not Hs - received: " + message.type
+ client.close()
+ return
+
+ print "Received message"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+ print str(message).encode("hex")
+ message = nfc.ndef.HandoverSelectMessage(message)
+ print "Handover select received"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+
+ for carrier in message.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.p2p":
+ print "P2P carrier type match - send to wpa_supplicant"
+ wpas_report_handover(data, carrier.record, "INIT")
+ break
+
+ print "Remove peer"
+ client.close()
+ print "Done with handover"
+ global only_one
+ if only_one:
+ print "only_one -> stop loop"
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait:
+ print "Trying to exit.."
+ global terminate_now
+ terminate_now = True
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+
+ def process_request(self, request):
+ self.ho_server_processing = True
+ clear_raw_mode()
+ print "HandoverServer - request received"
+ try:
+ print "Parsed handover request: " + request.pretty()
+ except Exception, e:
+ print e
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ found = False
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.p2p":
+ print "P2P carrier type match - add P2P carrier record"
+ found = True
+ self.received_carrier = carrier.record
+ print "Carrier record:"
+ try:
+ print carrier.record.pretty()
+ except Exception, e:
+ print e
+ data = wpas_get_handover_sel()
+ if data is None:
+ print "Could not get handover select carrier record from wpa_supplicant"
+ continue
+ print "Handover select carrier record from wpa_supplicant:"
+ print data.encode("hex")
+ self.sent_carrier = data
+ wpas_report_handover(self.received_carrier, self.sent_carrier,
+ "RESP")
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+ break
+
+ for carrier in request.carriers:
+ if found:
+ break
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WSC carrier type match - add WSC carrier record"
+ found = True
+ self.received_carrier = carrier.record
+ print "Carrier record:"
+ try:
+ print carrier.record.pretty()
+ except Exception, e:
+ print e
+ data = wpas_get_handover_sel_wps()
+ if data is None:
+ print "Could not get handover select carrier record from wpa_supplicant"
+ continue
+ print "Handover select carrier record from wpa_supplicant:"
+ print data.encode("hex")
+ self.sent_carrier = data
+ wpas_report_handover_wsc(self.received_carrier,
+ self.sent_carrier, "RESP")
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+ found = True
+ break
+
+ print "Handover select:"
+ try:
+ print sel.pretty()
+ except Exception, e:
+ print e
+ print str(sel).encode("hex")
+
+ print "Sending handover select"
+ self.success = True
+ return sel
+
+
+def clear_raw_mode():
+ import sys, tty, termios
+ global prev_tcgetattr, in_raw_mode
+ if not in_raw_mode:
+ return
+ fd = sys.stdin.fileno()
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+
+
+def getch():
+ import sys, tty, termios, select
+ global prev_tcgetattr, in_raw_mode
+ fd = sys.stdin.fileno()
+ prev_tcgetattr = termios.tcgetattr(fd)
+ ch = None
+ try:
+ tty.setraw(fd)
+ in_raw_mode = True
+ [i, o, e] = select.select([fd], [], [], 0.05)
+ if i:
+ ch = sys.stdin.read(1)
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+ return ch
+
+
+def p2p_tag_read(tag):
+ success = False
+ if len(tag.ndef.message):
+ for record in tag.ndef.message:
+ print "record type " + record.type
+ if record.type == "application/vnd.wfa.wsc":
+ print "WPS tag - send to wpa_supplicant"
+ success = wpas_tag_read(tag.ndef.message)
+ break
+ if record.type == "application/vnd.wfa.p2p":
+ print "P2P tag - send to wpa_supplicant"
+ success = wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ print "Empty tag"
+
+ return success
+
+
+def rdwr_connected_p2p_write(tag):
+ print "Tag found - writing"
+ global p2p_sel_data
+ tag.ndef.message = str(p2p_sel_data)
+ print "Done - remove tag"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global p2p_sel_wait_remove
+ return p2p_sel_wait_remove
+
+def wps_write_p2p_handover_sel(clf, wait_remove=True):
+ print "Write P2P handover select"
+ data = wpas_get_handover_sel(tag=True)
+ if (data == None):
+ print "Could not get P2P handover select from wpa_supplicant"
+ return
+
+ global p2p_sel_wait_remove
+ p2p_sel_wait_remove = wait_remove
+ global p2p_sel_data
+ p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
+ message = nfc.ndef.Message(data);
+ p2p_sel_data.add_carrier(message[0], "active", message[1:])
+ print "Handover select:"
+ try:
+ print p2p_sel_data.pretty()
+ except Exception, e:
+ print e
+ print str(p2p_sel_data).encode("hex")
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
+
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ print "Tag connected: " + str(tag)
+
+ if tag.ndef:
+ print "NDEF tag: " + tag.type
+ try:
+ print tag.ndef.message.pretty()
+ except Exception, e:
+ print e
+ success = p2p_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ print "Not an NDEF tag - remove tag"
+
+ return not no_wait
+
+
+def llcp_worker(llc):
+ global init_on_touch
+ if init_on_touch:
+ print "Starting handover client"
+ p2p_handover_client(llc)
+ return
+
+ global no_input
+ if no_input:
+ print "Wait for handover to complete"
+ else:
+ print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)"
+ global srv
+ global wait_connection
+ while not wait_connection and srv.sent_carrier is None:
+ if srv.ho_server_processing:
+ time.sleep(0.025)
+ elif no_input:
+ time.sleep(0.5)
+ else:
+ global include_wps_req, include_p2p_req
+ res = getch()
+ if res == 'i':
+ include_wps_req = True
+ include_p2p_req = True
+ elif res == 'p':
+ include_wps_req = False
+ include_p2p_req = True
+ elif res == 'w':
+ include_wps_req = True
+ include_p2p_req = False
+ else:
+ continue
+ clear_raw_mode()
+ print "Starting handover client"
+ p2p_handover_client(llc)
+ return
+
+ clear_raw_mode()
+ print "Exiting llcp_worker thread"
+
+def llcp_startup(clf, llc):
+ print "Start LLCP server"
+ global srv
+ srv = HandoverServer(llc)
+ return llc
+
+def llcp_connected(llc):
+ print "P2P LLCP connected"
+ global wait_connection
+ wait_connection = False
+ global init_on_touch
+ if not init_on_touch:
+ global srv
+ srv.start()
+ if init_on_touch or not no_input:
+ threading.Thread(target=llcp_worker, args=(llc,)).start()
+ return True
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--init-on-touch', '-I', action='store_true',
+ help='initiate handover on touch')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--ifname', '-i',
+ help='network interface name')
+ parser.add_argument('--no-wps-req', '-N', action='store_true',
+ help='do not include WPS carrier record in request')
+ parser.add_argument('--no-input', '-a', action='store_true',
+ help='do not use stdout input to initiate handover')
+ parser.add_argument('--tag-read-only', '-t', action='store_true',
+ help='tag read only (do not allow connection handover)')
+ parser.add_argument('--freq', '-f',
+ help='forced frequency of operating channel in MHz')
+ parser.add_argument('command', choices=['write-p2p-sel'],
+ nargs='?')
+ args = parser.parse_args()
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ global force_freq
+ force_freq = args.freq
+
+ logging.basicConfig(level=args.loglevel)
+
+ global init_on_touch
+ init_on_touch = args.init_on_touch
+
+ if args.ifname:
+ global ifname
+ ifname = args.ifname
+ print "Selected ifname " + ifname
+
+ if args.no_wps_req:
+ global include_wps_req
+ include_wps_req = False
+
+ if args.no_input:
+ global no_input
+ no_input = True
+
+ clf = nfc.ContactlessFrontend()
+ global wait_connection
+
+ try:
+ if not clf.open("usb"):
+ print "Could not open connection with an NFC device"
+ raise SystemExit
+
+ if args.command == "write-p2p-sel":
+ wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ print "Waiting for a tag or peer to be touched"
+ wait_connection = True
+ try:
+ if args.tag_read_only:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+ break
+ else:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected},
+ terminate=terminate_loop):
+ break
+ except Exception, e:
+ print "clf.connect failed"
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
new file mode 100644
index 0000000..59b0a9d
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+# Tests p2p_connect
+# Will try to connect to another peer
+# and form a group
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> -m <wps_method> \ " \
+ % sys.argv[0]
+ print " -a <addr> [-p <pin>] [-g <go_intent>] \ "
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -m = wps method"
+ print " -a = peer address"
+ print " -p = pin number (8 digits)"
+ print " -g = group owner intent"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]
+
+
+# Required Signals
+def GONegotiationSuccess(status):
+ print "Go Negotiation Success"
+
+def GONegotiationFailure(status):
+ print 'Go Negotiation Failed. Status:'
+ print format(status)
+ os._exit(0)
+
+def GroupStarted(properties):
+ if properties.has_key("group_object"):
+ print 'Group Formation Complete %s' \
+ % properties["group_object"]
+ os._exit(0)
+
+def WpsFailure(status, etc):
+ print "WPS Authentication Failure".format(status)
+ print etc
+ os._exit(0)
+
+class P2P_Connect():
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global ifname
+ global wpas
+ global wpas_dbus_interface
+ global timeout
+ global path
+ global wps_method
+ global go_intent
+ global addr
+ global pin
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Dictionary of Arguements
+ global p2p_connect_arguements
+
+ # Constructor
+ def __init__(self,ifname,wpas_dbus_interface,addr,
+ pin,wps_method,go_intent):
+ # Initializes variables and threads
+ self.ifname = ifname
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.wps_method = wps_method
+ self.go_intent = go_intent
+ self.addr = addr
+ self.pin = pin
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = \
+ "/" + self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = \
+ self.wpas_dbus_opath + "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(
+ self.wpas_object, self.wpas_dbus_interface)
+
+ # See if wpa_supplicant already knows about this interface
+ self.path = None
+ try:
+ self.path = self.wpas.GetInterface(ifname)
+ except:
+ if not str(exc).startswith(
+ self.wpas_dbus_interface + \
+ ".InterfaceUnknown:"):
+ raise exc
+ try:
+ path = self.wpas.CreateInterface(
+ {'Ifname': ifname, 'Driver': 'test'})
+ time.sleep(1)
+
+ except dbus.DBusException, exc:
+ if not str(exc).startswith(
+ self.wpas_dbus_interface + \
+ ".InterfaceExists:"):
+ raise exc
+
+ # Get Interface and objects
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface,self.path)
+ self.p2p_interface = dbus.Interface(
+ self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Add signals
+ self.bus.add_signal_receiver(GONegotiationSuccess,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GONegotiationSuccess")
+ self.bus.add_signal_receiver(GONegotiationFailure,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GONegotiationFailure")
+ self.bus.add_signal_receiver(GroupStarted,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GroupStarted")
+ self.bus.add_signal_receiver(WpsFailure,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="WpsFailed")
+
+
+ #Constructing all the arguements needed to connect
+ def constructArguements(self):
+ # Adding required arguements
+ self.p2p_connect_arguements = {'wps_method':self.wps_method,
+ 'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
+
+ # Display requires a pin, and a go intent of 15
+ if (self.wps_method == 'display'):
+ if (self.pin != None):
+ self.p2p_connect_arguements.update({'pin':self.pin})
+ else:
+ print "Error:\n Pin required for wps_method=display"
+ usage()
+ quit()
+
+ if (self.go_intent != None and int(self.go_intent) != 15):
+ print "go_intent overwritten to 15"
+
+ self.go_intent = '15'
+
+ # Keypad requires a pin, and a go intent of less than 15
+ elif (self.wps_method == 'keypad'):
+ if (self.pin != None):
+ self.p2p_connect_arguements.update({'pin':self.pin})
+ else:
+ print "Error:\n Pin required for wps_method=keypad"
+ usage()
+ quit()
+
+ if (self.go_intent != None and int(self.go_intent) == 15):
+ error = "Error :\n Group Owner intent cannot be" + \
+ " 15 for wps_method=keypad"
+ print error
+ usage()
+ quit()
+
+ # Doesn't require pin
+ # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad
+ elif (self.wps_method == 'pin'):
+ if (self.pin != None):
+ print "pin ignored"
+
+ # No pin is required for pbc so it is ignored
+ elif (self.wps_method == 'pbc'):
+ if (self.pin != None):
+ print "pin ignored"
+
+ else:
+ print "Error:\n wps_method not supported or does not exist"
+ usage()
+ quit()
+
+ # Go_intent is optional for all arguements
+ if (self.go_intent != None):
+ self.p2p_connect_arguements.update(
+ {'go_intent':dbus.Int32(self.go_intent)})
+
+ # Running p2p_connect
+ def run(self):
+ try:
+ result_pin = self.p2p_interface.Connect(
+ self.p2p_connect_arguements)
+
+ except dbus.DBusException, exc:
+ raise exc
+
+ if (self.wps_method == 'pin' and \
+ not self.p2p_connect_arguements.has_key('pin') ):
+ print "Connect return with pin value of %d " % int(result_pin)
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+ # Required
+ interface_name = None
+ wps_method = None
+ addr = None
+
+ # Conditionally optional
+ pin = None
+
+ # Optional
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+ go_intent = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:m:a:p:g:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # WPS Method
+ elif (key == "-m"):
+ wps_method = value
+ # Address
+ elif (key == "-a"):
+ addr = value
+ # Pin
+ elif (key == "-p"):
+ pin = value
+ # Group Owner Intent
+ elif (key == "-g"):
+ go_intent = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Required Arguements check
+ if (interface_name == None or wps_method == None or addr == None):
+ print "Error:\n Required arguements not specified"
+ usage()
+ quit()
+
+ # Group Owner Intent Check
+ if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ):
+ print "Error:\n Group Owner Intent must be between 0 and 15 inclusive"
+ usage()
+ quit()
+
+ # Pin Check
+ if (pin != None and len(pin) != 8):
+ print "Error:\n Pin is not 8 digits"
+ usage()
+ quit()
+
+ try:
+ p2p_connect_test = P2P_Connect(interface_name,wpas_dbus_interface,
+ addr,pin,wps_method,go_intent)
+
+ except:
+ print "Error:\n Invalid Arguements"
+ usage()
+ quit()
+
+ p2p_connect_test.constructArguements()
+ p2p_connect_test.run()
+
+ os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py
new file mode 100644
index 0000000..c3e39b3
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -0,0 +1,169 @@
+#!/usr/bin/python
+# Tests P2P_Disconnect
+# Will perform disconnect on interface_name
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i p2p-wlan0-0" % sys.argv[0]
+
+# Required Signals
+def GroupFinished(status, etc):
+ print "Disconnected"
+ os._exit(0)
+
+class P2P_Disconnect (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(GroupFinished,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GroupFinished")
+
+ # Runs p2p_disconnect
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.Disconnect()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_disconnect_test = P2P_Disconnect(interface_name,
+ wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Disconnect
+ p2p_disconnect_test.start()
+
+ try:
+ time.sleep(int(p2p_disconnect_test.timeout))
+
+ except:
+ pass
+
+ print "Disconnect timed out"
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py
new file mode 100644
index 0000000..973d46a
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_find.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+# Tests p2p_find
+# Will list all devices found/lost within a time frame (timeout)
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -t = timeout = 0s (infinite)"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0 -t 10" % sys.argv[0]
+
+# Required Signals
+def deviceFound(devicepath):
+ print "Device found: %s" % (devicepath)
+
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+class P2P_Find (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global timeout
+ global path
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.timeout = int(timeout)
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ #Adds listeners for find and lost
+ self.bus.add_signal_receiver(deviceFound,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceFound")
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+
+
+ # Sets up p2p_find
+ P2PFindDict = dbus.Dictionary(
+ {'Timeout':int(self.timeout)})
+ self.p2p_interface.Find(P2PFindDict)
+
+ # Run p2p_find
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+ # Defaults for optional inputs
+ timeout = 0
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:t:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Timeout
+ elif (key == "-t"):
+ if ( int(value) >= 0):
+ timeout = value
+ else:
+ print "Error:\n Timeout cannot be negative"
+ usage()
+ quit()
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_find_test.start()
+
+ try:
+ # If timeout is 0, then run forever
+ if (timeout == 0):
+ while(True):
+ pass
+ # Else sleep for (timeout)
+ else:
+ time.sleep(p2p_find_test.timeout)
+
+ except:
+ pass
+
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py
new file mode 100644
index 0000000..ff8509d
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# Tests P2P_Flush
+# Will flush the p2p interface
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals\
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+class P2P_Flush (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+
+ # Runs p2p_flush
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.Flush()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+ # Needed to show which devices were lost
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_flush_test.start()
+
+ try:
+ time.sleep(int(p2p_flush_test.timeout))
+
+ except:
+ pass
+
+ print "p2p_flush complete"
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py
new file mode 100644
index 0000000..5c8fdaf
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -0,0 +1,222 @@
+#!/usr/bin/python
+# Tests p2p_group_add
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+import threading
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> [-p <persistent>] \ " \
+ % sys.argv[0]
+ print " [-f <frequency>] [-o <group_object_path>] \ "
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -p = persistant group = 0 (0=false, 1=true)"
+ print " -f = frequency"
+ print " -o = persistent group object path"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def GroupStarted(properties):
+ if properties.has_key("group_object"):
+ print 'Group Formation Complete %s' \
+ % properties["group_object"]
+ os._exit(0)
+
+def WpsFailure(status, etc):
+ print "WPS Authentication Failure".format(status)
+ print etc
+ os._exit(0)
+
+class P2P_Group_Add (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global persistent
+ global frequency
+ global persistent_group_object
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Arguements
+ global P2PDictionary
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,persistent,frequency,
+ persistent_group_object):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.persistent = persistent
+ self.frequency = frequency
+ self.persistent_group_object = persistent_group_object
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ #Adds listeners
+ self.bus.add_signal_receiver(GroupStarted,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GroupStarted")
+ self.bus.add_signal_receiver(WpsFailure,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="WpsFailed")
+
+ # Sets up p2p_group_add dictionary
+ def constructArguements(self):
+ self.P2PDictionary = {'persistent':self.persistent}
+
+ if (self.frequency != None):
+ if (int(self.frequency) > 0):
+ self.P2PDictionary.update({'frequency':int(self.frequency)})
+ else:
+ print "Error:\n Frequency must be greater than 0"
+ usage()
+ os._exit(0)
+
+ if (self.persistent_group_object != None):
+ self.P2PDictionary.update({'persistent_group_object':
+ self.persistent_group_object})
+
+ # Run p2p_group_remove
+ def run(self):
+ try:
+ self.p2p_interface.GroupAdd(self.P2PDictionary)
+
+ except:
+ print "Error:\n Could not preform group add"
+ usage()
+ os._exit(0)
+
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+
+ # Defaults for optional inputs
+ # 0 = false, 1 = true
+ persistent = False
+ frequency = None
+ persistent_group_object = None
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:p:f:o:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Timeout
+ elif (key == "-p"):
+ if (value == '0'):
+ persistent = False
+ elif (value == '1'):
+ persistent = True
+ else:
+ print "Error:\n Persistent can only be 1 or 0"
+ usage()
+ os._exit(0)
+ # Frequency
+ elif (key == "-f"):
+ frequency = value
+ # Persistent group object path
+ elif (key == "-o"):
+ persistent_group_object = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ try:
+ p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
+ persistent,frequency,persistent_group_object)
+ except:
+ print "Error:\n Invalid Arguements"
+
+ p2p_group_add_test.constructArguements()
+ p2p_group_add_test.start()
+ time.sleep(5)
+ print "Error:\n Group formation timed out"
+ os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py
new file mode 100644
index 0000000..6deb397
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -0,0 +1,201 @@
+#!/usr/bin/python
+# Tests p2p_invite
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+import threading
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> -a <addr> \ " \
+ % sys.argv[0]
+ print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -a = address of peer"
+ print " -o = persistent group object path"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]
+
+# Required Signals
+def InvitationResult(invite_result):
+ print "Inviation Result signal :"
+ status = invite_result['status']
+ print "status = ", status
+ if invite_result.has_key('BSSID'):
+ bssid = invite_result['BSSID']
+ print "BSSID = ", hex(bssid[0]) , ":" , \
+ hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \
+ hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \
+ hex(bssid[5])
+ os._exit(0)
+
+class P2P_Invite (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global addr
+ global persistent_group_object
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Arguements
+ global P2PDictionary
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,addr,
+ persistent_group_object):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.addr = addr
+ self.persistent_group_object = persistent_group_object
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ #Adds listeners
+ self.bus.add_signal_receiver(InvitationResult,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="InvitationResult")
+
+ # Sets up p2p_invite dictionary
+ def constructArguements(self):
+ self.P2PDictionary = \
+ {'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
+ if (self.persistent_group_object != None):
+ self.P2PDictionary.update({"persistent_group_object":
+ self.persistent_group_object})
+
+ # Run p2p_invite
+ def run(self):
+ try:
+ self.p2p_interface.Invite(self.P2PDictionary)
+
+ except:
+ print "Error:\n Invalid Arguements"
+ usage()
+ os._exit(0)
+
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+ # Defaults for optional inputs
+ addr = None
+ persistent_group_object = None
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:o:w:a:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ elif (key == "-a"):
+ addr = value
+ # Persistent group object path
+ elif (key == "-o"):
+ persistent_group_object = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ if (addr == None):
+ print "Error:\n peer address is required"
+ usage()
+ quit()
+
+ try:
+ p2p_invite_test = \
+ P2P_Invite(interface_name,wpas_dbus_interface,
+ addr,persistent_group_object)
+ except:
+ print "Error:\n Invalid Arguements"
+ usage()
+ os._exit(1)
+
+ p2p_invite_test.constructArguements()
+ p2p_invite_test.start()
+ time.sleep(10)
+ print "Error:\n p2p_invite timed out"
+ os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py
new file mode 100644
index 0000000..bb3c1e4
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# Tests P2P_Find
+# Will listen
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -t = timeout = 0s (infinite)"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0 -t 5" % sys.argv[0]
+
+# Required Signals
+def p2pStateChange(status):
+ print status
+
+class P2P_Listen(threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.timeout = int(timeout)
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ self.bus.add_signal_receiver(p2pStateChange,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="P2PStateChanged")
+
+ # Run p2p_find
+ def run(self):
+ # Sets up p2p_listen
+ self.p2p_interface.Listen(int(self.timeout))
+
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+ # Defaults for optional inputs
+ timeout = 0
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:t:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Timeout
+ elif (key == "-t"):
+ if ( int(value) >= 0):
+ timeout = value
+ else:
+ print "Error:\n Timeout cannot be negative"
+ usage()
+ quit()
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_listen_test.start()
+
+ try:
+ # If timeout is 0, then run forever
+ if (int(p2p_listen_test.timeout) == 0):
+ while(True):
+ pass
+ # Else sleep for (timeout)
+ else:
+ time.sleep(int(p2p_listen_test.timeout))
+
+ except:
+ pass
+
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py
new file mode 100644
index 0000000..f6c03b0
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -0,0 +1,174 @@
+#!/usr/bin/python
+# Tests p2p_stop_find
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+def p2pStateChange(status):
+ print status
+ os._exit(0)
+
+class P2P_Stop_Find (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+ self.bus.add_signal_receiver(p2pStateChange,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="P2PStateChanged")
+
+ # Runs p2p_stop_find
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.StopFind()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+ # Needed because P2PStateChanged signal is not caught
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"ht:i:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_stop_find_test = P2P_Stop_Find(interface_name,
+ wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_stop_find_test.start()
+
+ try:
+ time.sleep(int(p2p_stop_find_test.timeout))
+
+ except:
+ pass
+
+ print "p2p find stopped"
+ quit()
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
new file mode 100644
index 0000000..7c6b0aa
--- /dev/null
+++ b/wpa_supplicant/examples/wps-ap-cli
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+CLI=wpa_cli
+
+pbc()
+{
+ echo "Starting PBC mode"
+ echo "Push button on the station within two minutes"
+ if ! $CLI wps_pbc | grep -q OK; then
+ echo "Failed to enable PBC mode"
+ fi
+}
+
+enter_pin()
+{
+ echo "Enter a PIN from a station to be enrolled to the network."
+ read -p "Enrollee PIN: " pin
+ cpin=`$CLI wps_check_pin "$pin" | tail -1`
+ if [ "$cpin" = "FAIL-CHECKSUM" ]; then
+ echo "Checksum digit is not valid"
+ read -p "Do you want to use this PIN (y/n)? " resp
+ case "$resp" in
+ y*)
+ cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ fi
+ if [ "$cpin" = "FAIL" ]; then
+ echo "Invalid PIN: $pin"
+ return 1
+ fi
+ echo "Enabling Enrollee PIN: $cpin"
+ $CLI wps_pin any "$cpin"
+}
+
+show_config()
+{
+ $CLI status wps
+}
+
+main_menu()
+{
+ echo "WPS AP"
+ echo "------"
+ echo "1: Push button (activate PBC)"
+ echo "2: Enter Enrollee PIN"
+ echo "3: Show current configuration"
+ echo "0: Exit wps-ap-cli"
+
+ read -p "Command: " cmd
+
+ case "$cmd" in
+ 1)
+ pbc
+ ;;
+ 2)
+ enter_pin
+ ;;
+ 3)
+ show_config
+ ;;
+ 0)
+ exit 0
+ ;;
+ *)
+ echo "Unknown command: $cmd"
+ ;;
+ esac
+
+ echo
+ main_menu
+}
+
+
+main_menu
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
new file mode 100644
index 0000000..35d1270
--- /dev/null
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -0,0 +1,460 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import random
+import threading
+import argparse
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+srv = None
+continue_loop = True
+terminate_now = False
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find wpa_supplicant: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No wpa_supplicant control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return False
+ if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
+ return False
+ return True
+
+def wpas_get_config_token(id=None):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if id:
+ ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id)
+ else:
+ ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+
+def wpas_get_er_config_token(uuid):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid)
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_req():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel(uuid):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if uuid is None:
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
+ else:
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip()
+ if "FAIL" in res:
+ return None
+ return res.decode("hex")
+
+
+def wpas_report_handover(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+
+ def process_request(self, request):
+ self.ho_server_processing = True
+ print "HandoverServer - request received"
+ try:
+ print "Parsed handover request: " + request.pretty()
+ except Exception, e:
+ print e
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - add WPS carrier record"
+ data = wpas_get_handover_sel(self.uuid)
+ if data is None:
+ print "Could not get handover select carrier record from wpa_supplicant"
+ continue
+ print "Handover select carrier record from wpa_supplicant:"
+ print data.encode("hex")
+ self.sent_carrier = data
+ wpas_report_handover(carrier.record, self.sent_carrier, "RESP")
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ try:
+ print sel.pretty()
+ except Exception, e:
+ print e
+ print str(sel).encode("hex")
+
+ print "Sending handover select"
+ self.success = True
+ return sel
+
+
+def wps_handover_init(llc):
+ print "Trying to initiate WPS handover"
+
+ data = wpas_get_handover_req()
+ if (data == None):
+ print "Could not get handover request carrier record from wpa_supplicant"
+ return
+ print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+
+ message = nfc.ndef.HandoverRequestMessage(version="1.2")
+ message.nonce = random.randint(0, 0xffff)
+ datamsg = nfc.ndef.Message(data)
+ message.add_carrier(datamsg[0], "active", datamsg[1:])
+
+ print "Handover request:"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+ print str(message).encode("hex")
+
+ client = nfc.handover.HandoverClient(llc)
+ try:
+ print "Trying handover";
+ client.connect()
+ print "Connected for handover"
+ except nfc.llcp.ConnectRefused:
+ print "Handover connection refused"
+ client.close()
+ return
+
+ print "Sending handover request"
+
+ if not client.send(message):
+ print "Failed to send handover request"
+
+ print "Receiving handover response"
+ message = client._recv()
+ if message is None:
+ print "No response received"
+ client.close()
+ return
+ if message.type != "urn:nfc:wkt:Hs":
+ print "Response was not Hs - received: " + message.type
+ client.close()
+ return
+
+ print "Received message"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+ print str(message).encode("hex")
+ message = nfc.ndef.HandoverSelectMessage(message)
+ print "Handover select received"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+
+ for carrier in message.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - send to wpa_supplicant"
+ wpas_report_handover(data, carrier.record, "INIT")
+ # nfcpy does not support the new format..
+ #wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+ #print wifi.pretty()
+
+ print "Remove peer"
+ client.close()
+ print "Done with handover"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait:
+ print "Trying to exit.."
+ global terminate_now
+ terminate_now = True
+
+def wps_tag_read(tag, wait_remove=True):
+ success = False
+ if len(tag.ndef.message):
+ for record in tag.ndef.message:
+ print "record type " + record.type
+ if record.type == "application/vnd.wfa.wsc":
+ print "WPS tag - send to wpa_supplicant"
+ success = wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ print "Empty tag"
+
+ if wait_remove:
+ print "Remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+ return success
+
+
+def rdwr_connected_write(tag):
+ print "Tag found - writing"
+ global write_data
+ tag.ndef.message = str(write_data)
+ print "Done - remove tag"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global write_wait_remove
+ while write_wait_remove and tag.is_present:
+ time.sleep(0.1)
+
+def wps_write_config_tag(clf, id=None, wait_remove=True):
+ print "Write WPS config token"
+ global write_data, write_wait_remove
+ write_wait_remove = wait_remove
+ write_data = wpas_get_config_token(id)
+ if write_data == None:
+ print "Could not get WPS config token from wpa_supplicant"
+ sys.exit(1)
+ return
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def wps_write_er_config_tag(clf, uuid, wait_remove=True):
+ print "Write WPS ER config token"
+ global write_data, write_wait_remove
+ write_wait_remove = wait_remove
+ write_data = wpas_get_er_config_token(uuid)
+ if write_data == None:
+ print "Could not get WPS config token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def wps_write_password_tag(clf, wait_remove=True):
+ print "Write WPS password token"
+ global write_data, write_wait_remove
+ write_wait_remove = wait_remove
+ write_data = wpas_get_password_token()
+ if write_data == None:
+ print "Could not get WPS password token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ print "Tag connected: " + str(tag)
+
+ if tag.ndef:
+ print "NDEF tag: " + tag.type
+ try:
+ print tag.ndef.message.pretty()
+ except Exception, e:
+ print e
+ success = wps_tag_read(tag, not only_one)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ print "Not an NDEF tag - remove tag"
+
+ return not no_wait
+
+
+def llcp_worker(llc):
+ global arg_uuid
+ if arg_uuid is None:
+ wps_handover_init(llc)
+ print "Exiting llcp_worker thread"
+ return
+
+ global srv
+ global wait_connection
+ while not wait_connection and srv.sent_carrier is None:
+ if srv.ho_server_processing:
+ time.sleep(0.025)
+
+def llcp_startup(clf, llc):
+ global arg_uuid
+ if arg_uuid:
+ print "Start LLCP server"
+ global srv
+ srv = HandoverServer(llc)
+ if arg_uuid is "ap":
+ print "Trying to handle WPS handover"
+ srv.uuid = None
+ else:
+ print "Trying to handle WPS handover with AP " + arg_uuid
+ srv.uuid = arg_uuid
+ return llc
+
+def llcp_connected(llc):
+ print "P2P LLCP connected"
+ global wait_connection
+ wait_connection = False
+ global arg_uuid
+ if arg_uuid:
+ global srv
+ srv.start()
+ else:
+ threading.Thread(target=llcp_worker, args=(llc,)).start()
+ print "llcp_connected returning"
+ return True
+
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--uuid',
+ help='UUID of an AP (used for WPS ER operations)')
+ parser.add_argument('--id',
+ help='network id (used for WPS ER operations)')
+ parser.add_argument('command', choices=['write-config',
+ 'write-er-config',
+ 'write-password'],
+ nargs='?')
+ args = parser.parse_args()
+
+ global arg_uuid
+ arg_uuid = args.uuid
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ logging.basicConfig(level=args.loglevel)
+
+ try:
+ if not clf.open("usb"):
+ print "Could not open connection with an NFC device"
+ raise SystemExit
+
+ if args.command == "write-config":
+ wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ if args.command == "write-er-config":
+ wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ if args.command == "write-password":
+ wps_write_password_tag(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ print "Waiting for a tag or peer to be touched"
+ wait_connection = True
+ try:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected},
+ terminate=terminate_loop):
+ break
+ except Exception, e:
+ print "clf.connect failed"
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 3b736da..abcb391 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -1,16 +1,11 @@
/*
* Generic advertisement service (GAS) query
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -19,17 +14,24 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "offchannel.h"
#include "gas_query.h"
-#define GAS_QUERY_TIMEOUT 5
+/** GAS query timeout in seconds */
+#define GAS_QUERY_TIMEOUT_PERIOD 2
+/**
+ * struct gas_query_pending - Pending GAS query
+ */
struct gas_query_pending {
struct dl_list list;
+ struct gas_query *gas;
u8 addr[ETH_ALEN];
u8 dialog_token;
u8 next_frag_id;
@@ -37,6 +39,7 @@ struct gas_query_pending {
unsigned int offchannel_tx_started:1;
int freq;
u16 status_code;
+ struct wpabuf *req;
struct wpabuf *adv_proto;
struct wpabuf *resp;
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -46,9 +49,14 @@ struct gas_query_pending {
void *ctx;
};
+/**
+ * struct gas_query - Internal GAS query data
+ */
struct gas_query {
struct wpa_supplicant *wpa_s;
struct dl_list pending; /* struct gas_query_pending */
+ struct gas_query_pending *current;
+ struct wpa_radio_work *work;
};
@@ -56,6 +64,11 @@ static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
static void gas_query_timeout(void *eloop_data, void *user_ctx);
+/**
+ * gas_query_init - Initialize GAS query component
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to GAS query data or %NULL on failure
+ */
struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
{
struct gas_query *gas;
@@ -71,10 +84,58 @@ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
}
+static const char * gas_result_txt(enum gas_query_result result)
+{
+ switch (result) {
+ case GAS_QUERY_SUCCESS:
+ return "SUCCESS";
+ case GAS_QUERY_FAILURE:
+ return "FAILURE";
+ case GAS_QUERY_TIMEOUT:
+ return "TIMEOUT";
+ case GAS_QUERY_PEER_ERROR:
+ 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";
+ }
+
+ return "N/A";
+}
+
+
+static void gas_query_free(struct gas_query_pending *query, int del_list)
+{
+ struct gas_query *gas = query->gas;
+
+ if (del_list)
+ dl_list_del(&query->list);
+
+ if (gas->work && gas->work->ctx == query) {
+ radio_work_done(gas->work);
+ gas->work = NULL;
+ }
+
+ wpabuf_free(query->req);
+ wpabuf_free(query->adv_proto);
+ wpabuf_free(query->resp);
+ os_free(query);
+}
+
+
static void gas_query_done(struct gas_query *gas,
struct gas_query_pending *query,
enum gas_query_result result)
{
+ wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR
+ " dialog_token=%u freq=%d status_code=%u result=%s",
+ MAC2STR(query->addr), query->dialog_token, query->freq,
+ query->status_code, gas_result_txt(result));
+ if (gas->current == query)
+ gas->current = NULL;
if (query->offchannel_tx_started)
offchannel_send_action_done(gas->wpa_s);
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
@@ -82,12 +143,14 @@ static void gas_query_done(struct gas_query *gas,
dl_list_del(&query->list);
query->cb(query->ctx, query->addr, query->dialog_token, result,
query->adv_proto, query->resp, query->status_code);
- wpabuf_free(query->adv_proto);
- wpabuf_free(query->resp);
- os_free(query);
+ gas_query_free(query, 0);
}
+/**
+ * gas_query_deinit - Deinitialize GAS query component
+ * @gas: GAS query data from gas_query_init()
+ */
void gas_query_deinit(struct gas_query *gas)
{
struct gas_query_pending *query, *next;
@@ -128,17 +191,70 @@ static int gas_query_append(struct gas_query_pending *query, const u8 *data,
}
+static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ struct gas_query_pending *query;
+ struct gas_query *gas = wpa_s->gas;
+
+ if (gas->current == NULL) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
+ MACSTR " result=%d - no query in progress",
+ freq, MAC2STR(dst), result);
+ return;
+ }
+
+ query = gas->current;
+
+ wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+ " result=%d query=%p dialog_token=%u",
+ freq, MAC2STR(dst), result, query, query->dialog_token);
+ if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
+ return;
+ }
+
+ if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+ }
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
+ }
+}
+
+
+static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ if (wpa_s->current_ssid == NULL ||
+ wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
+ os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0)
+ return 0;
+ return wpa_sm_pmf_enabled(wpa_s->wpa);
+}
+
+
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
struct wpabuf *req)
{
- int res;
+ int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
- "freq=%d", MAC2STR(query->addr),
- (unsigned int) wpabuf_len(req), query->freq);
+ "freq=%d prot=%d", MAC2STR(query->addr),
+ (unsigned int) wpabuf_len(req), query->freq, prot);
+ if (prot) {
+ u8 *categ = wpabuf_mhead_u8(req);
+ *categ = WLAN_ACTION_PROTECTED_DUAL;
+ }
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
gas->wpa_s->own_addr, query->addr,
wpabuf_head(req), wpabuf_len(req), 1000,
- NULL, 0);
+ gas_query_tx_status, 0);
if (res == 0)
query->offchannel_tx_started = 1;
return res;
@@ -261,6 +377,11 @@ static void gas_query_rx_comeback(struct gas_query *gas,
if (frag_id != query->next_frag_id) {
wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
"from " MACSTR, MAC2STR(query->addr));
+ if (frag_id + 1 == query->next_frag_id) {
+ wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
+ "retry of previous fragment");
+ return;
+ }
gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
return;
}
@@ -280,17 +401,42 @@ static void gas_query_rx_comeback(struct gas_query *gas,
}
+/**
+ * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
+ * @gas: GAS query data from gas_query_init()
+ * @da: Destination MAC address of the Action frame
+ * @sa: Source MAC address of the Action frame
+ * @bssid: BSSID of the Action frame
+ * @categ: Category of the Action frame
+ * @data: Payload of the Action frame
+ * @len: Length of @data
+ * @freq: Frequency (in MHz) on which the frame was received
+ * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
+ */
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
- const u8 *bssid, const u8 *data, size_t len, int freq)
+ const u8 *bssid, u8 categ, const u8 *data, size_t len,
+ int freq)
{
struct gas_query_pending *query;
u8 action, dialog_token, frag_id = 0, more_frags = 0;
u16 comeback_delay, resp_len;
const u8 *pos, *adv_proto;
+ int prot, pmf;
if (gas == NULL || len < 4)
return -1;
+ prot = categ == WLAN_ACTION_PROTECTED_DUAL;
+ pmf = pmf_in_use(gas->wpa_s, bssid);
+ if (prot && !pmf) {
+ wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
+ return 0;
+ }
+ if (!prot && pmf) {
+ wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled");
+ return 0;
+ }
+
pos = data;
action = *pos++;
dialog_token = *pos++;
@@ -400,8 +546,9 @@ static void gas_query_timeout(void *eloop_data, void *user_ctx)
struct gas_query *gas = eloop_data;
struct gas_query_pending *query = user_ctx;
- wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
- MAC2STR(query->addr));
+ wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
+ " dialog token %u",
+ MAC2STR(query->addr), query->dialog_token);
gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
}
@@ -420,6 +567,45 @@ static int gas_query_dialog_token_available(struct gas_query *gas,
}
+static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct gas_query_pending *query = work->ctx;
+ struct gas_query *gas = query->gas;
+
+ if (deinit) {
+ gas_query_free(query, 1);
+ return;
+ }
+
+ gas->work = work;
+
+ if (gas_query_tx(gas, query, query->req) < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+ MACSTR, MAC2STR(query->addr));
+ gas_query_free(query, 1);
+ return;
+ }
+ gas->current = query;
+
+ wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
+ query->dialog_token);
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+
+}
+
+
+/**
+ * gas_query_req - Request a GAS query
+ * @gas: GAS query data from gas_query_init()
+ * @dst: Destination MAC address for the query
+ * @freq: Frequency (in MHz) for the channel on which to send the query
+ * @req: GAS query payload (to be freed by gas_query module in case of success
+ * return)
+ * @cb: Callback function for reporting GAS query result and response
+ * @ctx: Context pointer to use with the @cb call
+ * Returns: dialog token (>= 0) on success or -1 on failure
+ */
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -430,46 +616,56 @@ 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, 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;
query = os_zalloc(sizeof(*query));
if (query == NULL)
return -1;
+ query->gas = gas;
os_memcpy(query->addr, dst, ETH_ALEN);
query->dialog_token = dialog_token;
query->freq = freq;
query->cb = cb;
query->ctx = ctx;
+ query->req = req;
dl_list_add(&gas->pending, &query->list);
*(wpabuf_mhead_u8(req) + 2) = dialog_token;
- wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
- " dialog_token %u", MAC2STR(dst), dialog_token);
- if (gas_query_tx(gas, query, req) < 0) {
- wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
- MACSTR, MAC2STR(query->addr));
- os_free(query);
+ wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
+ " dialog_token=%u freq=%d",
+ MAC2STR(query->addr), query->dialog_token, query->freq);
+
+ if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
+ query) < 0) {
+ gas_query_free(query, 1);
return -1;
}
- eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout,
- gas, query);
-
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;
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 64c3825..ad13490 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -3,14 +3,8 @@
* Copyright (c) 2009, Atheros Communications
* Copyright (c) 2011, Qualcomm Atheros
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef GAS_QUERY_H
@@ -23,8 +17,12 @@ struct gas_query;
struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
void gas_query_deinit(struct gas_query *gas);
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
- const u8 *bssid, const u8 *data, size_t len, int freq);
+ const u8 *bssid, u8 categ, const u8 *data, size_t len,
+ int freq);
+/**
+ * enum gas_query_result - GAS query result
+ */
enum gas_query_result {
GAS_QUERY_SUCCESS,
GAS_QUERY_FAILURE,
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
new file mode 100644
index 0000000..5f30313
--- /dev/null
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "config.h"
+#include "bss.h"
+#include "gas_query.h"
+#include "interworking.h"
+#include "hs20_supplicant.h"
+
+
+void wpas_hs20_add_indication(struct wpabuf *buf)
+{
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 5);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
+ wpabuf_put_u8(buf, 0x00); /* Hotspot Configuration */
+}
+
+
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss)
+{
+ if (!wpa_s->conf->hs20 || !ssid)
+ return 0;
+
+ if (ssid->parent_cred)
+ return 1;
+
+ if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE))
+ return 0;
+
+ /*
+ * This may catch some non-Hotspot 2.0 cases, but it is safer to do that
+ * than cause Hotspot 2.0 connections without indication element getting
+ * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element.
+ */
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X))
+ return 0;
+ if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP))
+ return 0;
+ if (ssid->proto != WPA_PROTO_RSN)
+ return 0;
+
+ return 1;
+}
+
+
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
+{
+ struct wpabuf *buf;
+ u8 *len_pos;
+
+ buf = gas_anqp_build_initial_req(0, 100 + payload_len);
+ if (buf == NULL)
+ return NULL;
+
+ len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) {
+ wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ if (payload)
+ wpabuf_put_data(buf, payload, payload_len);
+ } else {
+ u8 i;
+ wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ for (i = 0; i < 32; i++) {
+ if (stypes & BIT(i))
+ wpabuf_put_u8(buf, i);
+ }
+ }
+ gas_anqp_set_element_len(buf, len_pos);
+
+ gas_anqp_set_len(buf);
+
+ return buf;
+}
+
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+ const u8 *payload, size_t payload_len)
+{
+ struct wpabuf *buf;
+ int ret = 0;
+ int freq;
+ struct wpa_bss *bss;
+ int res;
+
+ freq = wpa_s->assoc_freq;
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+ if (bss) {
+ wpa_bss_anqp_unshare_alloc(bss);
+ freq = bss->freq;
+ }
+ if (freq <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for "
+ "subtypes 0x%x", MAC2STR(dst), stypes);
+
+ buf = hs20_build_anqp_req(stypes, payload, payload_len);
+ if (buf == NULL)
+ return -1;
+
+ res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
+ ret = -1;
+ } else
+ wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+ "%u", res);
+
+ return ret;
+}
+
+
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data, size_t slen)
+{
+ const u8 *pos = data;
+ u8 subtype;
+ struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+ struct wpa_bss_anqp *anqp = NULL;
+
+ if (slen < 2)
+ return;
+
+ if (bss)
+ anqp = bss->anqp;
+
+ subtype = *pos++;
+ slen--;
+
+ pos++; /* Reserved */
+ slen--;
+
+ switch (subtype) {
+ case HS20_STYPE_CAPABILITY_LIST:
+ 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);
+ break;
+ case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+ 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) {
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ anqp->hs20_operator_friendly_name =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_WAN_METRICS:
+ wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
+ if (slen < 13) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
+ "Metrics value from " MACSTR, MAC2STR(sa));
+ break;
+ }
+ 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));
+ if (anqp) {
+ wpabuf_free(anqp->hs20_wan_metrics);
+ anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_CONNECTION_CAPABILITY:
+ 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) {
+ wpabuf_free(anqp->hs20_connection_capability);
+ anqp->hs20_connection_capability =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_OPERATING_CLASS:
+ 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) {
+ wpabuf_free(anqp->hs20_operating_class);
+ anqp->hs20_operating_class =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
+ break;
+ }
+}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
new file mode 100644
index 0000000..1c8481b
--- /dev/null
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_SUPPLICANT_H
+#define HS20_SUPPLICANT_H
+
+void wpas_hs20_add_indication(struct wpabuf *buf);
+
+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);
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data, size_t slen);
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss);
+
+#endif /* HS20_SUPPLICANT_H */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index fc1a586..3083dd8 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -1,31 +1,44 @@
/*
* wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "common.h"
+#include "common/wpa_ctrl.h"
+#include "utils/eloop.h"
#include "l2_packet/l2_packet.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/wpa_ie.h"
#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
+#include "common/ieee802_11_defs.h"
#include "ibss_rsn.h"
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
+static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
+ const u8 *addr)
+{
+ struct ibss_rsn_peer *peer;
+
+ for (peer = ibss_rsn->peers; peer; peer = peer->next)
+ if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0)
+ break;
+ return peer;
+}
+
+
static void ibss_rsn_free(struct ibss_rsn_peer *peer)
{
+ eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
wpa_auth_sta_deinit(peer->auth);
wpa_sm_deinit(peer->supp);
os_free(peer);
@@ -107,6 +120,22 @@ static int supp_get_beacon_ie(void *ctx)
}
+static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
+{
+ struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+
+ if ((peer->authentication_status &
+ (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) !=
+ (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH))
+ return;
+ if (peer->authentication_status & IBSS_RSN_REPORTED_PTK)
+ return;
+ peer->authentication_status |= IBSS_RSN_REPORTED_PTK;
+ wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR,
+ MAC2STR(peer->addr));
+}
+
+
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,
@@ -121,6 +150,8 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
if (key_idx == 0) {
+ peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP;
+ ibss_check_rsn_completed(peer);
/*
* In IBSS RSN, the pairwise key from the 4-way handshake
* initiated by the peer with highest MAC address is used.
@@ -168,8 +199,8 @@ static void supp_deauthenticate(void * ctx, int reason_code)
}
-int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
- const u8 *psk)
+static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
+ const u8 *psk)
{
struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
@@ -226,7 +257,8 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
}
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
+static const u8 * auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk)
{
struct ibss_rsn *ibss_rsn = ctx;
wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
@@ -274,6 +306,15 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
if (idx == 0) {
+ if (addr) {
+ struct ibss_rsn_peer *peer;
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer) {
+ peer->authentication_status |=
+ IBSS_RSN_SET_PTK_AUTH;
+ ibss_check_rsn_completed(peer);
+ }
+ }
/*
* In IBSS RSN, the pairwise key from the 4-way handshake
* initiated by the peer with highest MAC address is used.
@@ -290,6 +331,13 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
}
+static void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason)
+{
+ struct ibss_rsn *ibss_rsn = ctx;
+ wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason);
+}
+
+
static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
void *ctx),
void *cb_ctx)
@@ -308,6 +356,53 @@ static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
}
+static void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn,
+ struct ibss_rsn_peer *peer, int authorized)
+{
+ int res;
+
+ if (authorized) {
+ res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr,
+ WPA_STA_AUTHORIZED,
+ WPA_STA_AUTHORIZED, ~0);
+ wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port",
+ MAC2STR(peer->addr));
+ } else {
+ res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr,
+ 0, 0, ~WPA_STA_AUTHORIZED);
+ wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port",
+ MAC2STR(peer->addr));
+ }
+
+ if (res && errno != ENOENT) {
+ wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags "
+ "for kernel driver (errno=%d)",
+ MAC2STR(peer->addr), errno);
+ }
+}
+
+
+static void auth_set_eapol(void *ctx, const u8 *addr,
+ wpa_eapol_variable var, int value)
+{
+ struct ibss_rsn *ibss_rsn = ctx;
+ struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr);
+
+ if (peer == NULL)
+ return;
+
+ switch (var) {
+ case WPA_EAPOL_authorized:
+ ibss_set_sta_authorized(ibss_rsn, peer, value);
+ break;
+ default:
+ /* do not handle any other event */
+ wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var);
+ break;
+ }
+}
+
+
static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
const u8 *own_addr)
{
@@ -328,10 +423,12 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
os_memset(&cb, 0, sizeof(cb));
cb.ctx = ibss_rsn;
cb.logger = auth_logger;
+ cb.set_eapol = auth_set_eapol;
cb.send_eapol = auth_send_eapol;
cb.get_psk = auth_get_psk;
cb.set_key = auth_set_key;
cb.for_each_sta = auth_for_each_sta;
+ cb.disconnect = ibss_rsn_disconnect;
ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
if (ibss_rsn->auth_group == NULL) {
@@ -348,7 +445,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
struct ibss_rsn_peer *peer)
{
- peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr);
+ peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr, NULL);
if (peer->auth == NULL) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
return -1;
@@ -376,47 +473,152 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
}
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
{
- struct ibss_rsn_peer *peer;
+ struct ieee80211_mgmt auth;
+ const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
+ struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
- if (ibss_rsn == NULL)
+ if (wpa_s->driver->send_frame == NULL)
return -1;
- for (peer = ibss_rsn->peers; peer; peer = peer->next) {
- if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) {
- wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and "
- "Supplicant for peer " MACSTR " already "
- "running", MAC2STR(addr));
- return 0;
- }
+ os_memset(&auth, 0, sizeof(auth));
+
+ auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ os_memcpy(auth.da, da, ETH_ALEN);
+ os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN);
+
+ auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN);
+ auth.u.auth.auth_transaction = host_to_le16(seq);
+ auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+
+ wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
+ seq, MAC2STR(da));
+
+ return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
+ auth_length, 0);
+}
+
+
+static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer)
+{
+ return peer->authentication_status &
+ (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US);
+}
+
+
+static struct ibss_rsn_peer *
+ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+ struct ibss_rsn_peer *peer;
+ if (ibss_rsn == NULL)
+ return NULL;
+
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR
+ " already running", MAC2STR(addr));
+ return peer;
}
- wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
- "Supplicant for peer " MACSTR, MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR,
+ MAC2STR(addr));
peer = os_zalloc(sizeof(*peer));
- if (peer == NULL)
- return -1;
+ if (peer == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory.");
+ return NULL;
+ }
peer->ibss_rsn = ibss_rsn;
os_memcpy(peer->addr, addr, ETH_ALEN);
+ peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED;
- if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk)
- < 0) {
+ if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr,
+ ibss_rsn->psk) < 0) {
ibss_rsn_free(peer);
+ return NULL;
+ }
+
+ peer->next = ibss_rsn->peers;
+ ibss_rsn->peers = peer;
+
+ return peer;
+}
+
+
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ibss_rsn_peer *peer = eloop_ctx;
+
+ /*
+ * Assume peer does not support Authentication exchange or the frame was
+ * lost somewhere - start EAPOL Authenticator.
+ */
+ wpa_printf(MSG_DEBUG,
+ "RSN: Timeout on waiting Authentication frame response from "
+ MACSTR " - start authenticator", MAC2STR(peer->addr));
+
+ peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+ ibss_rsn_auth_init(peer->ibss_rsn, peer);
+}
+
+
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+ struct ibss_rsn_peer *peer;
+ int res;
+
+ /* if the peer already exists, exit immediately */
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer)
+ return 0;
+
+ peer = ibss_rsn_peer_init(ibss_rsn, addr);
+ if (peer == NULL)
return -1;
+
+ /* Open Authentication: send first Authentication frame */
+ res = ibss_rsn_send_auth(ibss_rsn, addr, 1);
+ if (res) {
+ /*
+ * The driver may not support Authentication frame exchange in
+ * IBSS. Ignore authentication and go through EAPOL exchange.
+ */
+ peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+ return ibss_rsn_auth_init(ibss_rsn, peer);
+ } else {
+ os_get_reltime(&peer->own_auth_tx);
+ eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL);
}
- if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
- ibss_rsn_free(peer);
+ return 0;
+}
+
+
+static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn,
+ struct ibss_rsn_peer *peer, int reason)
+{
+ int already_started;
+
+ if (ibss_rsn == NULL || peer == NULL)
return -1;
+
+ already_started = ibss_rsn_is_auth_started(peer);
+ peer->authentication_status |= reason;
+
+ if (already_started) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already "
+ "started for peer " MACSTR, MAC2STR(peer->addr));
+ return 0;
}
- peer->next = ibss_rsn->peers;
- ibss_rsn->peers = peer;
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
+ "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
- return 0;
+ return ibss_rsn_auth_init(ibss_rsn, peer);
}
@@ -557,10 +759,21 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
return -1;
os_memcpy(tmp, buf, len);
if (supp) {
- wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant");
+ peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
+ MACSTR, MAC2STR(peer->addr));
wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
} else {
- wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator");
+ if (ibss_rsn_is_auth_started(peer) == 0) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
+ "Authenticator dropped as " MACSTR " is not "
+ "authenticated", MAC2STR(peer->addr));
+ os_free(tmp);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator "
+ "from "MACSTR, MAC2STR(peer->addr));
wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
}
os_free(tmp);
@@ -577,19 +790,25 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
if (ibss_rsn == NULL)
return -1;
- for (peer = ibss_rsn->peers; peer; peer = peer->next) {
- if (os_memcmp(src_addr, peer->addr, ETH_ALEN) == 0)
- return ibss_rsn_process_rx_eapol(ibss_rsn, peer,
- buf, len);
- }
+ peer = ibss_rsn_get_peer(ibss_rsn, src_addr);
+ if (peer)
+ return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len);
if (ibss_rsn_eapol_dst_supp(buf, len) > 0) {
/*
* Create new IBSS peer based on an EAPOL message from the peer
* Authenticator.
*/
- if (ibss_rsn_start(ibss_rsn, src_addr) < 0)
+ peer = ibss_rsn_peer_init(ibss_rsn, src_addr);
+ if (peer == NULL)
return -1;
+
+ /* assume the peer is authenticated already */
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer "
+ MACSTR, MAC2STR(src_addr));
+ ibss_rsn_peer_authenticated(ibss_rsn, peer,
+ IBSS_RSN_AUTH_EAPOL_BY_US);
+
return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
buf, len);
}
@@ -597,10 +816,101 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
return 0;
}
-
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
{
if (ibss_rsn == NULL)
return;
os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
}
+
+
+static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
+ struct ibss_rsn_peer *peer,
+ const u8* addr)
+{
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR,
+ MAC2STR(addr));
+
+ if (peer &&
+ peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
+ if (peer->own_auth_tx.sec) {
+ struct os_reltime now, diff;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &peer->own_auth_tx, &diff);
+ if (diff.sec == 0 && diff.usec < 500000) {
+ wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX",
+ (int) diff.usec);
+ goto skip_reinit;
+ }
+ }
+ /*
+ * A peer sent us an Authentication frame even though it already
+ * started an EAPOL session. We should reinit state machines
+ * here, but it's much more complicated than just deleting and
+ * recreating the state machine
+ */
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station "
+ MACSTR, MAC2STR(addr));
+
+ ibss_rsn_stop(ibss_rsn, addr);
+ peer = NULL;
+ }
+
+ if (!peer) {
+ peer = ibss_rsn_peer_init(ibss_rsn, addr);
+ if (!peer)
+ return;
+
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR,
+ MAC2STR(addr));
+ }
+
+skip_reinit:
+ /* reply with an Authentication frame now, before sending an EAPOL */
+ ibss_rsn_send_auth(ibss_rsn, addr, 2);
+ /* no need to start another AUTH challenge in the other way.. */
+ ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US);
+}
+
+
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+ size_t len)
+{
+ const struct ieee80211_mgmt *header;
+ struct ibss_rsn_peer *peer;
+ size_t auth_length;
+
+ header = (const struct ieee80211_mgmt *) auth_frame;
+ auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
+
+ if (ibss_rsn == NULL || len < auth_length)
+ return;
+
+ if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN ||
+ le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS)
+ return;
+
+ peer = ibss_rsn_get_peer(ibss_rsn, header->sa);
+
+ switch (le_to_host16(header->u.auth.auth_transaction)) {
+ case 1:
+ ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa);
+ break;
+ case 2:
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from "
+ MACSTR, MAC2STR(header->sa));
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from "
+ "unknown STA " MACSTR, MAC2STR(header->sa));
+ break;
+ }
+
+ /* authentication has been completed */
+ eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR,
+ MAC2STR(header->sa));
+ ibss_rsn_peer_authenticated(ibss_rsn, peer,
+ IBSS_RSN_AUTH_BY_US);
+ break;
+ }
+}
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index dbc889f..67fae2d 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -2,14 +2,8 @@
* wpa_supplicant - IBSS RSN
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef IBSS_RSN_H
@@ -17,6 +11,21 @@
struct ibss_rsn;
+/* not authenticated */
+#define IBSS_RSN_AUTH_NOT_AUTHENTICATED 0x00
+/* remote peer sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_PEER 0x01
+/* we sent an AUTH message with seq 1 */
+#define IBSS_RSN_AUTH_BY_US 0x02
+/* we sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_US 0x04
+/* PTK derived as supplicant */
+#define IBSS_RSN_SET_PTK_SUPP 0x08
+/* PTK derived as authenticator */
+#define IBSS_RSN_SET_PTK_AUTH 0x10
+/* PTK completion reported */
+#define IBSS_RSN_REPORTED_PTK 0x20
+
struct ibss_rsn_peer {
struct ibss_rsn_peer *next;
struct ibss_rsn *ibss_rsn;
@@ -29,6 +38,9 @@ struct ibss_rsn_peer {
size_t supp_ie_len;
struct wpa_state_machine *auth;
+ int authentication_status;
+
+ struct os_reltime own_auth_tx;
};
struct ibss_rsn {
@@ -46,5 +58,7 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
const u8 *buf, size_t len);
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+ size_t len);
#endif /* IBSS_RSN_H */
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 5897ce4..da8971d 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1,15 +1,10 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -18,15 +13,22 @@
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
#include "common/wpa_ctrl.h"
+#include "utils/pcsc_funcs.h"
+#include "utils/eloop.h"
#include "drivers/driver.h"
#include "eap_common/eap_defs.h"
+#include "eap_peer/eap.h"
#include "eap_peer/eap_methods.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "config.h"
+#include "config_ssid.h"
#include "bss.h"
#include "scan.h"
#include "notify.h"
#include "gas_query.h"
+#include "hs20_supplicant.h"
#include "interworking.h"
@@ -43,6 +45,27 @@
#endif
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+
+
+static void interworking_reconnect(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+
+ if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+ return;
+
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
@@ -85,29 +108,137 @@ static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
}
+static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->roaming_consortium_len)
+ return 1;
+ if (cred->required_roaming_consortium_len)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->pcsc || cred->imsi)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->pcsc || cred->imsi)
+ continue;
+ if (!cred->eap_method)
+ return 1;
+ if (cred->realm && cred->roaming_consortium_len == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_domain(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->domain || cred->pcsc || cred->imsi)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int additional_roaming_consortiums(struct wpa_bss *bss)
+{
+ const u8 *ie;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ if (ie == NULL || ie[1] == 0)
+ return 0;
+ return ie[2]; /* Number of ANQP OIs */
+}
+
+
+static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ interworking_next_anqp_fetch(wpa_s);
+}
+
+
static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
struct wpabuf *buf;
int ret = 0;
int res;
- u16 info_ids[] = {
- ANQP_CAPABILITY_LIST,
- ANQP_VENUE_NAME,
- ANQP_NETWORK_AUTH_TYPE,
- ANQP_ROAMING_CONSORTIUM,
- ANQP_IP_ADDR_TYPE_AVAILABILITY,
- ANQP_NAI_REALM,
- ANQP_3GPP_CELLULAR_NETWORK,
- ANQP_DOMAIN_NAME
- };
+ u16 info_ids[8];
+ size_t num_info_ids = 0;
struct wpabuf *extra = NULL;
+ int all = wpa_s->fetch_all_anqp;
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+ wpa_s->interworking_gas_bss = bss;
+
+ info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
+ if (all) {
+ info_ids[num_info_ids++] = ANQP_VENUE_NAME;
+ info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
+ }
+ if (all || (cred_with_roaming_consortium(wpa_s) &&
+ additional_roaming_consortiums(bss)))
+ info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
+ if (all)
+ info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
+ if (all || cred_with_nai_realm(wpa_s))
+ info_ids[num_info_ids++] = ANQP_NAI_REALM;
+ if (all || cred_with_3gpp(wpa_s))
+ info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
+ if (all || cred_with_domain(wpa_s))
+ info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
+ wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
+ (u8 *) info_ids, num_info_ids * 2);
+
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ u8 *len_pos;
+
+ extra = wpabuf_alloc(100);
+ if (!extra)
+ return -1;
+
+ len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(extra, OUI_WFA);
+ wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
+ wpabuf_put_u8(extra, 0); /* Reserved */
+ wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
+ if (all) {
+ wpabuf_put_u8(extra,
+ HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+ wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+ wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+ }
+ gas_anqp_set_element_len(extra, len_pos);
+ }
+#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
- extra);
+ buf = anqp_build_req(info_ids, num_info_ids, extra);
wpabuf_free(extra);
if (buf == NULL)
return -1;
@@ -116,12 +247,14 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
+ eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
+ NULL);
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
@@ -280,11 +413,9 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
return NULL;
}
wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
- r->realm = os_malloc(realm_len + 1);
+ r->realm = dup_binstr(pos, realm_len);
if (r->realm == NULL)
return NULL;
- os_memcpy(r->realm, pos, realm_len);
- r->realm[realm_len] = '\0';
pos += realm_len;
if (pos + 1 > f_end) {
@@ -297,7 +428,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
wpa_printf(MSG_DEBUG, "No room for EAP Methods");
return NULL;
}
- r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
+ r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
if (r->eap == NULL)
return NULL;
@@ -333,7 +464,7 @@ static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
return NULL;
}
- realm = os_zalloc(num * sizeof(struct nai_realm));
+ realm = os_calloc(num, sizeof(struct nai_realm));
if (realm == NULL)
return NULL;
@@ -390,18 +521,24 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap)
if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
return 0; /* method not supported */
- if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
+ if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
+ eap->method != EAP_TYPE_FAST) {
/* Only tunneled methods with username/password supported */
return 0;
}
- if (eap->method == EAP_TYPE_PEAP &&
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
- return 0;
+ if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
+ if (eap->inner_method &&
+ eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+ return 0;
+ if (!eap->inner_method &&
+ eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
+ return 0;
+ }
if (eap->method == EAP_TYPE_TTLS) {
if (eap->inner_method == 0 && eap->inner_non_eap == 0)
- return 0;
+ return 1; /* Assume TTLS/MSCHAPv2 is used */
if (eap->inner_method &&
eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
return 0;
@@ -422,20 +559,41 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap)
}
-struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
- struct nai_realm *realm)
+static int nai_realm_cred_cert(struct nai_realm_eap *eap)
+{
+ if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+ return 0; /* method not supported */
+
+ if (eap->method != EAP_TYPE_TLS) {
+ /* Only EAP-TLS supported for credential authentication */
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
+ struct nai_realm *realm)
{
u8 e;
- if (wpa_s->conf->home_username == NULL ||
- wpa_s->conf->home_username[0] == '\0' ||
- wpa_s->conf->home_password == NULL ||
- wpa_s->conf->home_password[0] == '\0')
+ if (cred == NULL ||
+ cred->username == NULL ||
+ cred->username[0] == '\0' ||
+ ((cred->password == NULL ||
+ cred->password[0] == '\0') &&
+ (cred->private_key == NULL ||
+ cred->private_key[0] == '\0')))
return NULL;
for (e = 0; e < realm->eap_count; e++) {
struct nai_realm_eap *eap = &realm->eap[e];
- if (nai_realm_cred_username(eap))
+ if (cred->password && cred->password[0] &&
+ nai_realm_cred_username(eap))
+ return eap;
+ if (cred->private_key && cred->private_key[0] &&
+ nai_realm_cred_cert(eap))
return eap;
}
@@ -445,25 +603,31 @@ struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
#ifdef INTERWORKING_3GPP
-static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
{
- const char *sep;
- u8 plmn[3];
+ u8 plmn[3], plmn2[3];
const u8 *pos, *end;
u8 udhl;
- sep = os_strchr(imsi, '-');
- if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6))
- return 0;
-
- /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
+ /*
+ * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
+ * operator is allowed to include only two digits of the MNC, so allow
+ * matches based on both two and three digit MNC assumptions. Since some
+ * SIM/USIM cards may not expose MNC length conveniently, we may be
+ * provided the default MNC length 3 here and as such, checking with MNC
+ * length 2 is justifiable even though 3GPP TS 24.234 does not mention
+ * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
+ * with otherwise matching values would not be good idea in general, so
+ * this should not result in selecting incorrect networks.
+ */
+ /* Match with 3 digit MNC */
plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
- plmn[1] = imsi[2] - '0';
- if (sep - imsi == 6)
- plmn[1] |= (imsi[5] - '0') << 4;
- else
- plmn[1] |= 0xf0;
+ plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+ /* Match with 2 digit MNC */
+ plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
+ plmn2[1] = (imsi[2] - '0') | 0xf0;
+ plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
if (anqp == NULL)
return 0;
@@ -483,6 +647,10 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
}
end = pos + udhl;
+ wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
+ plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
+ imsi, mnc_len);
+
while (pos + 2 <= end) {
u8 iei, len;
const u8 *l_end;
@@ -495,14 +663,20 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
if (iei == 0 && len > 0) {
/* PLMN List */
u8 num, i;
+ wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
+ pos, len);
num = *pos++;
for (i = 0; i < num; i++) {
- if (pos + 3 > end)
+ if (pos + 3 > l_end)
break;
- if (os_memcmp(pos, plmn, 3) == 0)
+ if (os_memcmp(pos, plmn, 3) == 0 ||
+ os_memcmp(pos, plmn2, 3) == 0)
return 1; /* Found matching PLMN */
pos += 3;
}
+ } else {
+ wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
+ pos, len);
}
pos = l_end;
@@ -512,10 +686,11 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
}
-static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
+ size_t mnc_len, char prefix)
{
const char *sep, *msin;
- char nai[100], *end, *pos;
+ char *end, *pos;
size_t msin_len, plmn_len;
/*
@@ -530,17 +705,22 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
return -1;
}
sep = os_strchr(imsi, '-');
- if (sep == NULL)
+ if (sep) {
+ plmn_len = sep - imsi;
+ msin = sep + 1;
+ } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
+ plmn_len = 3 + mnc_len;
+ msin = imsi + plmn_len;
+ } else
return -1;
- plmn_len = sep - imsi;
if (plmn_len != 5 && plmn_len != 6)
return -1;
- msin = sep + 1;
msin_len = os_strlen(msin);
pos = nai;
- end = pos + sizeof(nai);
- *pos++ = prefix;
+ end = nai + nai_len;
+ if (prefix)
+ *pos++ = prefix;
os_memcpy(pos, imsi, plmn_len);
pos += plmn_len;
os_memcpy(pos, msin, msin_len);
@@ -558,64 +738,188 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
imsi[0], imsi[1], imsi[2]);
+ return 0;
+}
+
+
+static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+{
+ char nai[100];
+ if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
+ return -1;
return wpa_config_set_quoted(ssid, "identity", nai);
}
#endif /* INTERWORKING_3GPP */
+static int already_connected(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
+ return 0;
+
+ ssid = wpa_s->current_ssid;
+ if (ssid->parent_cred != cred)
+ return 0;
+
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+ return 0;
+
+ return 1;
+}
+
+
+static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid->parent_cred != cred)
+ continue;
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+ continue;
+
+ break;
+ }
+
+ if (ssid == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+}
+
+
+static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (wpa_config_set(ssid, "key_mgmt",
+ wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
+ "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
+ return -1;
+ if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
+ return -1;
+ if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ return -1;
+ return 0;
+}
+
+
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
struct wpa_bss *bss)
{
#ifdef INTERWORKING_3GPP
struct wpa_ssid *ssid;
- const u8 *ie;
+ int eap_type;
+ int res;
+ char prefix;
- ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
- if (ie == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
+
wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
MAC2STR(bss->bssid));
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
+
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
+ ssid->parent_cred = cred;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
ssid->temporary = 1;
- ssid->ssid = os_zalloc(ie[1] + 1);
+ ssid->ssid = os_zalloc(bss->ssid_len + 1);
if (ssid->ssid == NULL)
goto fail;
- os_memcpy(ssid->ssid, ie + 2, ie[1]);
- ssid->ssid_len = ie[1];
+ os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+ ssid->ssid_len = bss->ssid_len;
- /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
- if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
- wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
+ if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
+
+ eap_type = EAP_TYPE_SIM;
+ if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
+ eap_type = EAP_TYPE_AKA;
+ if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
+ if (cred->eap_method[0].method == EAP_TYPE_SIM ||
+ cred->eap_method[0].method == EAP_TYPE_AKA ||
+ cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
+ eap_type = cred->eap_method[0].method;
+ }
+
+ switch (eap_type) {
+ case EAP_TYPE_SIM:
+ prefix = '1';
+ res = wpa_config_set(ssid, "eap", "SIM", 0);
+ break;
+ case EAP_TYPE_AKA:
+ prefix = '0';
+ res = wpa_config_set(ssid, "eap", "AKA", 0);
+ break;
+ case EAP_TYPE_AKA_PRIME:
+ prefix = '6';
+ res = wpa_config_set(ssid, "eap", "AKA'", 0);
+ break;
+ default:
+ res = -1;
+ break;
}
- if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
+ eap_type);
+ goto fail;
+ }
+
+ if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
goto fail;
}
- if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
+ if (cred->milenage && cred->milenage[0]) {
if (wpa_config_set_quoted(ssid, "password",
- wpa_s->conf->home_milenage) < 0)
+ cred->milenage) < 0)
goto fail;
- } else {
- /* TODO: PIN */
+ } else if (cred->pcsc) {
if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
goto fail;
+ if (wpa_s->conf->pcsc_pin &&
+ wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
+ < 0)
+ goto fail;
}
- if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
- wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
- < 0)
+ if (cred->password && cred->password[0] &&
+ wpa_config_set_quoted(ssid, "password", cred->password) < 0)
goto fail;
- wpa_supplicant_select_network(wpa_s, ssid);
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
return 0;
@@ -627,46 +931,411 @@ fail:
}
+static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
+ size_t rc_len)
+{
+ const u8 *pos, *end;
+ u8 lens;
+
+ if (ie == NULL)
+ return 0;
+
+ pos = ie + 2;
+ end = ie + 2 + ie[1];
+
+ /* Roaming Consortium element:
+ * Number of ANQP OIs
+ * OI #1 and #2 lengths
+ * OI #1, [OI #2], [OI #3]
+ */
+
+ if (pos + 2 > end)
+ return 0;
+
+ pos++; /* skip Number of ANQP OIs */
+ lens = *pos++;
+ if (pos + (lens & 0x0f) + (lens >> 4) > end)
+ return 0;
+
+ if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += lens & 0x0f;
+
+ if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += lens >> 4;
+
+ if (pos < end && (size_t) (end - pos) == rc_len &&
+ os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+
+ return 0;
+}
+
+
+static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
+ const u8 *rc_id, size_t rc_len)
+{
+ const u8 *pos, *end;
+ u8 len;
+
+ if (anqp == NULL)
+ return 0;
+
+ pos = wpabuf_head(anqp);
+ end = pos + wpabuf_len(anqp);
+
+ /* Set of <OI Length, OI> duples */
+ while (pos < end) {
+ len = *pos++;
+ if (pos + len > end)
+ break;
+ if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += len;
+ }
+
+ return 0;
+}
+
+
+static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
+ const u8 *rc_id, size_t rc_len)
+{
+ return roaming_consortium_element_match(ie, rc_id, rc_len) ||
+ roaming_consortium_anqp_match(anqp, rc_id, rc_len);
+}
+
+
+static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (cred->required_roaming_consortium_len == 0)
+ return 0;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+ if (ie == NULL &&
+ (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ return 1;
+
+ return !roaming_consortium_match(ie,
+ bss->anqp ?
+ bss->anqp->roaming_consortium : NULL,
+ cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len);
+}
+
+
+static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ size_t i;
+
+ if (!cred->excluded_ssid)
+ return 0;
+
+ for (i = 0; i < cred->num_excluded_ssid; i++) {
+ struct excluded_ssid *e = &cred->excluded_ssid[i];
+ if (bss->ssid_len == e->ssid_len &&
+ os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static struct wpa_cred * interworking_credentials_available_roaming_consortium(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_cred *cred, *selected = NULL;
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+ if (ie == NULL &&
+ (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ return NULL;
+
+ if (wpa_s->conf->cred == NULL)
+ return NULL;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->roaming_consortium_len == 0)
+ continue;
+
+ if (!roaming_consortium_match(ie,
+ bss->anqp ?
+ bss->anqp->roaming_consortium :
+ NULL,
+ cred->roaming_consortium,
+ cred->roaming_consortium_len))
+ continue;
+
+ if (cred_excluded_ssid(cred, bss))
+ continue;
+ if (cred_no_required_oi_match(cred, bss))
+ continue;
+
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ }
+
+ return selected;
+}
+
+
+static int interworking_set_eap_params(struct wpa_ssid *ssid,
+ struct wpa_cred *cred, int ttls)
+{
+ if (cred->eap_method) {
+ ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
+ cred->eap_method->method == EAP_TYPE_TTLS;
+
+ os_free(ssid->eap.eap_methods);
+ ssid->eap.eap_methods =
+ os_malloc(sizeof(struct eap_method_type) * 2);
+ if (ssid->eap.eap_methods == NULL)
+ return -1;
+ os_memcpy(ssid->eap.eap_methods, cred->eap_method,
+ sizeof(*cred->eap_method));
+ ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
+ ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
+ }
+
+ if (ttls && cred->username && cred->username[0]) {
+ const char *pos;
+ char *anon;
+ /* Use anonymous NAI in Phase 1 */
+ pos = os_strchr(cred->username, '@');
+ if (pos) {
+ size_t buflen = 9 + os_strlen(pos) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous%s", pos);
+ } else if (cred->realm) {
+ size_t buflen = 10 + os_strlen(cred->realm) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+ } else {
+ anon = os_strdup("anonymous");
+ if (anon == NULL)
+ return -1;
+ }
+ if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
+ 0) {
+ os_free(anon);
+ return -1;
+ }
+ os_free(anon);
+ }
+
+ if (cred->username && cred->username[0] &&
+ wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
+ return -1;
+
+ if (cred->password && cred->password[0]) {
+ if (cred->ext_password &&
+ wpa_config_set(ssid, "password", cred->password, 0) < 0)
+ return -1;
+ if (!cred->ext_password &&
+ wpa_config_set_quoted(ssid, "password", cred->password) <
+ 0)
+ return -1;
+ }
+
+ if (cred->client_cert && cred->client_cert[0] &&
+ wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
+ return -1;
+
+#ifdef ANDROID
+ if (cred->private_key &&
+ os_strncmp(cred->private_key, "keystore://", 11) == 0) {
+ /* Use OpenSSL engine configuration for Android keystore */
+ if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
+ wpa_config_set_quoted(ssid, "key_id",
+ cred->private_key + 11) < 0 ||
+ wpa_config_set(ssid, "engine", "1", 0) < 0)
+ return -1;
+ } else
+#endif /* ANDROID */
+ if (cred->private_key && cred->private_key[0] &&
+ wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+ return -1;
+
+ if (cred->private_key_passwd && cred->private_key_passwd[0] &&
+ wpa_config_set_quoted(ssid, "private_key_passwd",
+ cred->private_key_passwd) < 0)
+ return -1;
+
+ if (cred->phase1) {
+ os_free(ssid->eap.phase1);
+ ssid->eap.phase1 = os_strdup(cred->phase1);
+ }
+ if (cred->phase2) {
+ os_free(ssid->eap.phase2);
+ ssid->eap.phase2 = os_strdup(cred->phase2);
+ }
+
+ if (cred->ca_cert && cred->ca_cert[0] &&
+ wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
+ return -1;
+
+ if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
+ wpa_config_set_quoted(ssid, "domain_suffix_match",
+ cred->domain_suffix_match) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int interworking_connect_roaming_consortium(
+ struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
+ struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
+ "roaming consortium match", MAC2STR(bss->bssid));
+
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL)
+ return -1;
+ ssid->parent_cred = cred;
+ wpas_notify_network_added(wpa_s, ssid);
+ wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
+ ssid->temporary = 1;
+ ssid->ssid = os_zalloc(bss->ssid_len + 1);
+ if (ssid->ssid == NULL)
+ goto fail;
+ os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+ ssid->ssid_len = bss->ssid_len;
+
+ if (interworking_set_hs20_params(wpa_s, ssid) < 0)
+ goto fail;
+
+ if (cred->eap_method == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
+ "credential using roaming consortium");
+ goto fail;
+ }
+
+ if (interworking_set_eap_params(
+ ssid, cred,
+ cred->eap_method->vendor == EAP_VENDOR_IETF &&
+ cred->eap_method->method == EAP_TYPE_TTLS) < 0)
+ goto fail;
+
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
+
+ return 0;
+
+fail:
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return -1;
+}
+
+
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
+ struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
struct nai_realm *realm;
struct nai_realm_eap *eap = NULL;
u16 count, i;
char buf[100];
- const u8 *ie;
- if (bss == NULL)
+ if (wpa_s->conf->cred == NULL || bss == NULL)
return -1;
- ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
- if (ie == NULL || ie[1] == 0) {
- wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
MACSTR, MAC2STR(bss->bssid));
return -1;
}
- realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+ /*
+ * We currently support only HS 2.0 networks and those are
+ * required to use WPA2-Enterprise.
+ */
+ wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
+ "RSN");
+ return -1;
+ }
+
+ cred_rc = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred_rc) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
+ "consortium matching credential priority %d",
+ cred_rc->priority);
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss);
+ if (cred) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
+ "matching credential priority %d",
+ cred->priority);
+ }
+
+ cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
+ if (cred_3gpp) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
+ "credential priority %d", cred_3gpp->priority);
+ }
+
+ if (cred_rc &&
+ (cred == NULL || cred_rc->priority >= cred->priority) &&
+ (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
+ return interworking_connect_roaming_consortium(wpa_s, cred_rc,
+ bss);
+
+ if (cred_3gpp &&
+ (cred == NULL || cred_3gpp->priority >= cred->priority)) {
+ return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+ }
+
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+ "found for " MACSTR, MAC2STR(bss->bssid));
+ return -1;
+ }
+
+ realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
+ &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
- count = 0;
+ return -1;
}
for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+ if (!nai_realm_match(&realm[i], cred->realm))
continue;
- eap = nai_realm_find_eap(wpa_s, &realm[i]);
+ eap = nai_realm_find_eap(cred, &realm[i]);
if (eap)
break;
}
if (!eap) {
- if (interworking_connect_3gpp(wpa_s, bss) == 0) {
- if (realm)
- nai_realm_free(realm, count);
- return 0;
- }
-
wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
"and EAP method found for " MACSTR,
MAC2STR(bss->bssid));
@@ -677,32 +1346,36 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
MAC2STR(bss->bssid));
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ nai_realm_free(realm, count);
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
+
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
nai_realm_free(realm, count);
return -1;
}
+ ssid->parent_cred = cred;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
ssid->temporary = 1;
- ssid->ssid = os_zalloc(ie[1] + 1);
+ ssid->ssid = os_zalloc(bss->ssid_len + 1);
if (ssid->ssid == NULL)
goto fail;
- os_memcpy(ssid->ssid, ie + 2, ie[1]);
- ssid->ssid_len = ie[1];
+ os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+ ssid->ssid_len = bss->ssid_len;
- if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
- eap->method), 0) < 0)
- goto fail;
-
- if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
- wpa_config_set_quoted(ssid, "identity",
- wpa_s->conf->home_username) < 0)
+ if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
- if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
- wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
- < 0)
+ if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
+ eap->method), 0) < 0)
goto fail;
switch (eap->method) {
@@ -736,24 +1409,42 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
0) < 0)
goto fail;
break;
+ default:
+ /* EAP params were not set - assume TTLS/MSCHAPv2 */
+ if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
+ 0) < 0)
+ goto fail;
+ break;
}
break;
case EAP_TYPE_PEAP:
+ case EAP_TYPE_FAST:
+ if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"",
+ 0) < 0)
+ goto fail;
+ if (wpa_config_set(ssid, "pac_file",
+ "\"blob://pac_interworking\"", 0) < 0)
+ goto fail;
os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
+ eap_get_name(EAP_VENDOR_IETF,
+ eap->inner_method ?
+ eap->inner_method :
+ EAP_TYPE_MSCHAPV2));
if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
goto fail;
break;
+ case EAP_TYPE_TLS:
+ break;
}
- if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
- wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
- 0)
+ if (interworking_set_eap_params(ssid, cred,
+ eap->method == EAP_TYPE_TTLS) < 0)
goto fail;
nai_realm_free(realm, count);
- wpa_supplicant_select_network(wpa_s, ssid);
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
return 0;
@@ -765,92 +1456,383 @@ fail:
}
-static int interworking_credentials_available_3gpp(
+static struct wpa_cred * interworking_credentials_available_3gpp(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- int ret = 0;
-
+ struct wpa_cred *selected = NULL;
#ifdef INTERWORKING_3GPP
- if (bss->anqp_3gpp == NULL)
- return ret;
+ struct wpa_cred *cred;
+ int ret;
- if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] ||
- wpa_s->conf->home_milenage == NULL ||
- !wpa_s->conf->home_milenage[0])
- return ret;
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+ return NULL;
- wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR,
- MAC2STR(bss->bssid));
- ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi);
- wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+#ifdef CONFIG_EAP_PROXY
+ if (!wpa_s->imsi[0]) {
+ size_t len;
+ wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+ wpa_s->imsi,
+ &len);
+ if (wpa_s->mnc_len > 0) {
+ wpa_s->imsi[len] = '\0';
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+ } else {
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+ }
+ }
+#endif /* CONFIG_EAP_PROXY */
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ char *sep;
+ const char *imsi;
+ int mnc_len;
+ char imsi_buf[16];
+ size_t msin_len;
+
+#ifdef PCSC_FUNCS
+ if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+ wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ goto compare;
+ }
+#endif /* PCSC_FUNCS */
+#ifdef CONFIG_EAP_PROXY
+ if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ goto compare;
+ }
+#endif /* CONFIG_EAP_PROXY */
+
+ if (cred->imsi == NULL || !cred->imsi[0] ||
+ (!wpa_s->conf->external_sim &&
+ (cred->milenage == NULL || !cred->milenage[0])))
+ continue;
+
+ sep = os_strchr(cred->imsi, '-');
+ if (sep == NULL ||
+ (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+ continue;
+ mnc_len = sep - cred->imsi - 3;
+ os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
+ sep++;
+ msin_len = os_strlen(cred->imsi);
+ if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
+ msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
+ os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
+ imsi_buf[3 + mnc_len + msin_len] = '\0';
+ imsi = imsi_buf;
+
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
+ compare:
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
+ wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
+ MACSTR, MAC2STR(bss->bssid));
+ ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
+ wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+ if (ret) {
+ if (cred_excluded_ssid(cred, bss))
+ continue;
+ if (cred_no_required_oi_match(cred, bss))
+ continue;
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ }
+ }
#endif /* INTERWORKING_3GPP */
- return ret;
+ return selected;
}
-static int interworking_credentials_available_realm(
+static struct wpa_cred * interworking_credentials_available_realm(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
+ struct wpa_cred *cred, *selected = NULL;
struct nai_realm *realm;
u16 count, i;
- int found = 0;
- if (bss->anqp_nai_realm == NULL)
- return 0;
+ if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
+ return NULL;
- if (wpa_s->conf->home_realm == NULL)
- return 0;
+ if (wpa_s->conf->cred == NULL)
+ return NULL;
wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
MACSTR, MAC2STR(bss->bssid));
- realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+ realm = nai_realm_parse(bss->anqp->nai_realm, &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
- return 0;
+ return NULL;
}
- for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->realm == NULL)
continue;
- if (nai_realm_find_eap(wpa_s, &realm[i])) {
- found++;
- break;
+
+ for (i = 0; i < count; i++) {
+ if (!nai_realm_match(&realm[i], cred->realm))
+ continue;
+ if (nai_realm_find_eap(cred, &realm[i])) {
+ if (cred_excluded_ssid(cred, bss))
+ continue;
+ if (cred_no_required_oi_match(cred, bss))
+ continue;
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ break;
+ }
}
}
nai_realm_free(realm, count);
- return found;
+ return selected;
+}
+
+
+static struct wpa_cred * interworking_credentials_available(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_cred *cred, *cred2;
+
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
+ MACSTR, MAC2STR(bss->bssid));
+ return NULL;
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss);
+ cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
+ if (cred && cred2 && cred2->priority >= cred->priority)
+ cred = cred2;
+ if (!cred)
+ cred = cred2;
+
+ cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred && cred2 && cred2->priority >= cred->priority)
+ cred = cred2;
+ if (!cred)
+ cred = cred2;
+
+ return cred;
+}
+
+
+static int domain_name_list_contains(struct wpabuf *domain_names,
+ const char *domain)
+{
+ const u8 *pos, *end;
+ size_t len;
+
+ len = os_strlen(domain);
+ pos = wpabuf_head(domain_names);
+ end = pos + wpabuf_len(domain_names);
+
+ while (pos + 1 < end) {
+ if (pos + 1 + pos[0] > end)
+ 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)
+ return 1;
+
+ pos += 1 + pos[0];
+ }
+
+ return 0;
+}
+
+
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpabuf *domain_names)
+{
+ size_t i;
+ int ret = -1;
+#ifdef INTERWORKING_3GPP
+ char nai[100], *realm;
+
+ char *imsi = NULL;
+ int mnc_len = 0;
+ if (cred->imsi)
+ imsi = cred->imsi;
+#ifdef CONFIG_PCSC
+ else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
+ wpa_s->scard && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+#endif /* CONFIG_PCSC */
+#ifdef CONFIG_EAP_PROXY
+ else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+#endif /* CONFIG_EAP_PROXY */
+ if (domain_names &&
+ imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
+ realm = os_strchr(nai, '@');
+ if (realm)
+ realm++;
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match "
+ "with SIM/USIM domain %s", realm);
+ if (realm &&
+ domain_name_list_contains(domain_names, realm))
+ return 1;
+ if (realm)
+ ret = 0;
+ }
+#endif /* INTERWORKING_3GPP */
+
+ if (domain_names == NULL || cred->domain == NULL)
+ return ret;
+
+ for (i = 0; i < cred->num_domain; i++) {
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+ "home SP FQDN %s", cred->domain[i]);
+ if (domain_name_list_contains(domain_names, cred->domain[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int interworking_home_sp(struct wpa_supplicant *wpa_s,
+ struct wpabuf *domain_names)
+{
+ struct wpa_cred *cred;
+
+ if (domain_names == NULL || wpa_s->conf->cred == NULL)
+ return -1;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
+ if (res)
+ return res;
+ }
+
+ return 0;
}
-static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss)
+static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
{
- return interworking_credentials_available_realm(wpa_s, bss) ||
- interworking_credentials_available_3gpp(wpa_s, bss);
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid) ||
+ ssid->mode != WPAS_MODE_INFRA)
+ continue;
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
+ 0)
+ continue;
+ /*
+ * TODO: Consider more accurate matching of security
+ * configuration similarly to what is done in events.c
+ */
+ return 1;
+ }
+ }
+
+ return 0;
}
static void interworking_select_network(struct wpa_supplicant *wpa_s)
{
- struct wpa_bss *bss, *selected = NULL;
+ struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
+ int selected_prio = -999999, selected_home_prio = -999999;
unsigned int count = 0;
+ const char *type;
+ int res;
+ struct wpa_cred *cred;
wpa_s->network_select = 0;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- if (!interworking_credentials_available(wpa_s, bss))
+ cred = interworking_credentials_available(wpa_s, bss);
+ if (!cred)
+ continue;
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+ /*
+ * We currently support only HS 2.0 networks and those
+ * are required to use WPA2-Enterprise.
+ */
+ wpa_printf(MSG_DEBUG, "Interworking: Credential match "
+ "with " MACSTR " but network does not use "
+ "RSN", MAC2STR(bss->bssid));
continue;
+ }
count++;
- wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
- MAC2STR(bss->bssid));
- if (selected == NULL && wpa_s->auto_select)
- selected = bss;
+ res = interworking_home_sp(wpa_s, bss->anqp ?
+ bss->anqp->domain_name : NULL);
+ if (res > 0)
+ type = "home";
+ else if (res == 0)
+ type = "roaming";
+ else
+ type = "unknown";
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
+ MAC2STR(bss->bssid), type);
+ if (wpa_s->auto_select ||
+ (wpa_s->conf->auto_interworking &&
+ wpa_s->auto_network_select)) {
+ if (selected == NULL ||
+ cred->priority > selected_prio) {
+ selected = bss;
+ selected_prio = cred->priority;
+ }
+ if (res > 0 &&
+ (selected_home == NULL ||
+ cred->priority > selected_home_prio)) {
+ selected_home = bss;
+ selected_home_prio = cred->priority;
+ }
+ }
+ }
+
+ if (selected_home && selected_home != selected &&
+ selected_home_prio >= selected_prio) {
+ /* Prefer network operated by the Home SP */
+ selected = selected_home;
}
if (count == 0) {
+ /*
+ * No matching network was found based on configured
+ * credentials. Check whether any of the enabled network blocks
+ * have matching APs.
+ */
+ if (interworking_find_network_match(wpa_s)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
+ "match for enabled network configurations");
+ if (wpa_s->auto_select)
+ interworking_reconnect(wpa_s);
+ return;
+ }
+
+ if (wpa_s->auto_network_select) {
+ wpa_printf(MSG_DEBUG, "Interworking: Continue "
+ "scanning after ANQP fetch");
+ wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
+ 0);
+ return;
+ }
+
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
"with matching credentials found");
}
@@ -860,13 +1842,50 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
}
+static struct wpa_bss_anqp *
+interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_bss *other;
+
+ if (is_zero_ether_addr(bss->hessid))
+ return NULL; /* Cannot be in the same homegenous ESS */
+
+ dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
+ if (other == bss)
+ continue;
+ if (other->anqp == NULL)
+ continue;
+ if (other->anqp->roaming_consortium == NULL &&
+ other->anqp->nai_realm == NULL &&
+ other->anqp->anqp_3gpp == NULL &&
+ other->anqp->domain_name == NULL)
+ continue;
+ if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
+ continue;
+ if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
+ continue;
+ if (bss->ssid_len != other->ssid_len ||
+ os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
+ "already fetched BSSID " MACSTR " and " MACSTR,
+ MAC2STR(other->bssid), MAC2STR(bss->bssid));
+ other->anqp->users++;
+ return other->anqp;
+ }
+
+ return NULL;
+}
+
+
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
int found = 0;
const u8 *ie;
- if (!wpa_s->fetch_anqp_in_progress)
+ if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
return;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
@@ -875,8 +1894,22 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
continue; /* AP does not support Interworking */
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
+ continue; /* Disallowed BSS */
if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+ if (bss->anqp == NULL) {
+ bss->anqp = interworking_match_anqp_info(wpa_s,
+ bss);
+ if (bss->anqp) {
+ /* Shared data already fetched */
+ continue;
+ }
+ bss->anqp = wpa_bss_anqp_alloc();
+ if (bss->anqp == NULL)
+ break;
+ }
found++;
bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
@@ -895,7 +1928,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
}
-static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@@ -913,6 +1946,7 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
return 0;
wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
interworking_start_fetch_anqp(wpa_s);
@@ -940,8 +1974,10 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
freq = wpa_s->assoc_freq;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (bss)
+ if (bss) {
+ wpa_bss_anqp_unshare_alloc(bss);
freq = bss->freq;
+ }
if (freq <= 0)
return -1;
@@ -955,22 +1991,29 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, u16 info_id,
+ struct wpa_bss *bss, const u8 *sa,
+ u16 info_id,
const u8 *data, size_t slen)
{
const u8 *pos = data;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+ struct wpa_bss_anqp *anqp = NULL;
+#ifdef CONFIG_HS20
+ u8 type;
+#endif /* CONFIG_HS20 */
+
+ if (bss)
+ anqp = bss->anqp;
switch (info_id) {
case ANQP_CAPABILITY_LIST:
@@ -981,9 +2024,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_venue_name);
- bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->venue_name);
+ anqp->venue_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_NETWORK_AUTH_TYPE:
@@ -992,10 +2035,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
"Type", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_network_auth_type);
- bss->anqp_network_auth_type =
- wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->network_auth_type);
+ anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_ROAMING_CONSORTIUM:
@@ -1003,10 +2045,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_roaming_consortium);
- bss->anqp_roaming_consortium =
- wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->roaming_consortium);
+ anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
@@ -1015,9 +2056,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_ip_addr_type_availability);
- bss->anqp_ip_addr_type_availability =
+ if (anqp) {
+ wpabuf_free(anqp->ip_addr_type_availability);
+ anqp->ip_addr_type_availability =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -1025,9 +2066,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
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 (bss) {
- wpabuf_free(bss->anqp_nai_realm);
- bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->nai_realm);
+ anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
@@ -1035,18 +2076,18 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_3gpp);
- bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->anqp_3gpp);
+ anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_DOMAIN_NAME:
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 (bss) {
- wpabuf_free(bss->anqp_domain_name);
- bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->domain_name);
+ anqp->domain_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_VENDOR_SPECIFIC:
@@ -1054,6 +2095,28 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
return;
switch (WPA_GET_BE24(pos)) {
+#ifdef CONFIG_HS20
+ case OUI_WFA:
+ pos += 3;
+ slen -= 3;
+
+ if (slen < 1)
+ return;
+ type = *pos++;
+ slen--;
+
+ switch (type) {
+ case HS20_ANQP_OUI_TYPE:
+ hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
+ slen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
+ "vendor type %u", type);
+ break;
+ }
+ break;
+#endif /* CONFIG_HS20 */
default:
wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
"vendor-specific ANQP OUI %06x",
@@ -1079,6 +2142,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
const u8 *end;
u16 info_id;
u16 slen;
+ struct wpa_bss *bss = NULL, *tmp;
if (result != GAS_QUERY_SUCCESS)
return;
@@ -1091,6 +2155,21 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
return;
}
+ /*
+ * If possible, select the BSS entry based on which BSS entry was used
+ * for the request. This can help in cases where multiple BSS entries
+ * may exist for the same AP.
+ */
+ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
+ if (tmp == wpa_s->interworking_gas_bss &&
+ os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (bss == NULL)
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+
pos = wpabuf_head(resp);
end = pos + wpabuf_len(resp);
@@ -1108,7 +2187,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
"for Info ID %u", info_id);
break;
}
- interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+ interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}
@@ -1124,16 +2203,110 @@ static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
}
-int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
+ int *freqs)
{
interworking_stop_fetch_anqp(wpa_s);
wpa_s->network_select = 1;
+ wpa_s->auto_network_select = 0;
wpa_s->auto_select = !!auto_select;
+ wpa_s->fetch_all_anqp = 0;
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
- wpa_s->scan_req = 2;
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = freqs;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return 0;
}
+
+
+static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpabuf *n;
+
+ wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
+ " dialog_token=%d status_code=%d resp_len=%d",
+ MAC2STR(addr), dialog_token, status_code,
+ resp ? (int) wpabuf_len(resp) : -1);
+ if (!resp)
+ return;
+
+ n = wpabuf_dup(resp);
+ if (n == NULL)
+ return;
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = wpa_s->last_gas_resp;
+ os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN);
+ wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token;
+ wpa_s->last_gas_resp = n;
+ os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
+ wpa_s->last_gas_dialog_token = dialog_token;
+}
+
+
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *query)
+{
+ struct wpabuf *buf;
+ int ret = 0;
+ int freq;
+ struct wpa_bss *bss;
+ int res;
+ size_t len;
+ u8 query_resp_len_limit = 0, pame_bi = 0;
+
+ freq = wpa_s->assoc_freq;
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+ if (bss)
+ freq = bss->freq;
+ if (freq <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
+ MAC2STR(dst), freq);
+ wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
+
+ len = 3 + wpabuf_len(adv_proto) + 2;
+ if (query)
+ len += wpabuf_len(query);
+ buf = gas_build_initial_req(0, len);
+ if (buf == NULL)
+ return -1;
+
+ /* Advertisement Protocol IE */
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
+ wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+ (pame_bi ? 0x80 : 0));
+ wpabuf_put_buf(buf, adv_proto);
+
+ /* GAS Query */
+ if (query) {
+ wpabuf_put_le16(buf, wpabuf_len(query));
+ wpabuf_put_buf(buf, query);
+ } else
+ wpabuf_put_le16(buf, 0);
+
+ res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpabuf_free(buf);
+ ret = -1;
+ } else
+ wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
+ "%u", res);
+
+ return ret;
+}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 247df30..c8e7093 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -1,15 +1,9 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef INTERWORKING_H
@@ -23,9 +17,17 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code);
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *query);
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
-int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
+ int *freqs);
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpabuf *domain_names);
#endif /* INTERWORKING_H */
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index e196f3c..d56935d 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant / main() function for UNIX like OSes and MinGW
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -20,8 +14,7 @@
#include "common.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
+#include "p2p_supplicant.h"
static void usage(void)
@@ -29,16 +22,29 @@ static void usage(void)
int i;
printf("%s\n\n%s\n"
"usage:\n"
- " wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
+ " wpa_supplicant [-BddhKLqq"
+#ifdef CONFIG_DEBUG_SYSLOG
+ "s"
+#endif /* CONFIG_DEBUG_SYSLOG */
+ "t"
+#ifdef CONFIG_DBUS
+ "u"
+#endif /* CONFIG_DBUS */
+ "vW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
+ " [-G<group>] \\\n"
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
"[-p<driver_param>] \\\n"
- " [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
- "\\\n"
+ " [-b<br_ifname>] [-e<entropy file>]"
+#ifdef CONFIG_DEBUG_FILE
+ " [-f<debug file>]"
+#endif /* CONFIG_DEBUG_FILE */
+ " \\\n"
" [-o<override driver>] [-O<override ctrl>] \\\n"
" [-N -i<ifname> -c<conf> [-C<ctrl>] "
"[-D<driver>] \\\n"
- " [-p<driver_param>] [-b<br_ifname>] ...]\n"
+ " [-p<driver_param>] [-b<br_ifname>] [-I<config file>] "
+ "...]\n"
"\n"
"drivers:\n",
wpa_supplicant_version, wpa_supplicant_license);
@@ -56,6 +62,7 @@ static void usage(void)
" -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");
@@ -63,13 +70,18 @@ static void usage(void)
printf(" -f = log output to debug file instead of stdout\n");
#endif /* CONFIG_DEBUG_FILE */
printf(" -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"
- " -L = show license (GPL and BSD)\n"
+ " -L = show license (BSD)\n"
" -o = override driver parameter for new interfaces\n"
" -O = override ctrl_interface parameter for new interfaces\n"
" -p = driver parameters\n"
@@ -84,7 +96,7 @@ static void usage(void)
printf("example:\n"
" wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
- wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
+ wpa_drivers[0] ? wpa_drivers[0]->name : "nl80211");
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -103,20 +115,31 @@ static void license(void)
}
-static void wpa_supplicant_fd_workaround(void)
+static void wpa_supplicant_fd_workaround(int start)
{
#ifdef __linux__
- int s, i;
+ static int fd[3] = { -1, -1, -1 };
+ int i;
/* When started from pcmcia-cs scripts, wpa_supplicant might start with
* fd 0, 1, and 2 closed. This will cause some issues because many
* places in wpa_supplicant are still printing out to stdout. As a
* workaround, make sure that fd's 0, 1, and 2 are not used for other
* sockets. */
- for (i = 0; i < 3; i++) {
- s = open("/dev/null", O_RDWR);
- if (s > 2) {
- close(s);
- break;
+ if (start) {
+ for (i = 0; i < 3; i++) {
+ fd[i] = open("/dev/null", O_RDWR);
+ if (fd[i] > 2) {
+ close(fd[i]);
+ fd[i] = -1;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 3; i++) {
+ if (fd[i] >= 0) {
+ close(fd[i]);
+ fd[i] = -1;
+ }
}
}
#endif /* __linux__ */
@@ -142,10 +165,11 @@ int main(int argc, char *argv[])
return -1;
iface_count = 1;
- wpa_supplicant_fd_workaround();
+ wpa_supplicant_fd_workaround(1);
for (;;) {
- c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
+ c = getopt(argc, argv,
+ "b:Bc:C:D:de:f:g:G:hi:I:KLNo:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -185,6 +209,9 @@ int main(int argc, char *argv[])
case 'g':
params.ctrl_interface = optarg;
break;
+ case 'G':
+ params.ctrl_interface_group = optarg;
+ break;
case 'h':
usage();
exitcode = 0;
@@ -192,6 +219,9 @@ int main(int argc, char *argv[])
case 'i':
iface->ifname = optarg;
break;
+ case 'I':
+ iface->confanother = optarg;
+ break;
case 'K':
params.wpa_debug_show_keys++;
break;
@@ -220,6 +250,11 @@ int main(int argc, char *argv[])
params.wpa_debug_syslog++;
break;
#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ case 'T':
+ params.wpa_debug_tracing++;
+ break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 't':
params.wpa_debug_timestamp++;
break;
@@ -237,8 +272,8 @@ int main(int argc, char *argv[])
break;
case 'N':
iface_count++;
- iface = os_realloc(ifaces, iface_count *
- sizeof(struct wpa_interface));
+ iface = os_realloc_array(ifaces, iface_count,
+ sizeof(struct wpa_interface));
if (iface == NULL)
goto out;
ifaces = iface;
@@ -258,9 +293,14 @@ int main(int argc, char *argv[])
wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
exitcode = -1;
goto out;
+ } else {
+ wpa_printf(MSG_INFO, "Successfully initialized "
+ "wpa_supplicant");
}
for (i = 0; exitcode == 0 && i < iface_count; i++) {
+ struct wpa_supplicant *wpa_s;
+
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
@@ -271,8 +311,18 @@ int main(int argc, char *argv[])
exitcode = -1;
break;
}
- if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+ wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
+ if (wpa_s == NULL) {
+ exitcode = -1;
+ break;
+ }
+#ifdef CONFIG_P2P
+ if (wpa_s->global->p2p == NULL &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+ wpas_p2p_add_p2pdev_interface(wpa_s) < 0)
exitcode = -1;
+#endif /* CONFIG_P2P */
}
if (exitcode == 0)
@@ -281,6 +331,7 @@ int main(int argc, char *argv[])
wpa_supplicant_deinit(global);
out:
+ wpa_supplicant_fd_workaround(0);
os_free(ifaces);
os_free(params.pid_file);
diff --git a/wpa_supplicant/main_none.c b/wpa_supplicant/main_none.c
index 993338a..010c30a 100644
--- a/wpa_supplicant/main_none.c
+++ b/wpa_supplicant/main_none.c
@@ -2,14 +2,8 @@
* WPA Supplicant / Example program entrypoint
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
diff --git a/wpa_supplicant/main_symbian.cpp b/wpa_supplicant/main_symbian.cpp
deleted file mode 100644
index 4ff364b..0000000
--- a/wpa_supplicant/main_symbian.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * WPA Supplicant / Program entrypoint for Symbian
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-extern "C" {
-#include "common.h"
-#include "wpa_supplicant_i.h"
-}
-
-GLDEF_C TInt E32Main(void)
-{
- struct wpa_interface iface;
- int exitcode = 0;
- struct wpa_params params;
- struct wpa_global *global;
-
- memset(&params, 0, sizeof(params));
- params.wpa_debug_level = MSG_INFO;
-
- global = wpa_supplicant_init(&params);
- if (global == NULL)
- return -1;
-
- memset(&iface, 0, sizeof(iface));
- /* TODO: set interface parameters */
-
- if (wpa_supplicant_add_iface(global, &iface) == NULL)
- exitcode = -1;
-
- if (exitcode == 0)
- exitcode = wpa_supplicant_run(global);
-
- wpa_supplicant_deinit(global);
-
- return exitcode;
-}
diff --git a/wpa_supplicant/main_winmain.c b/wpa_supplicant/main_winmain.c
index 19d9950..93a68f1 100644
--- a/wpa_supplicant/main_winmain.c
+++ b/wpa_supplicant/main_winmain.c
@@ -2,14 +2,8 @@
* WPA Supplicant / WinMain() function for Windows-based applications
* Copyright (c) 2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
diff --git a/wpa_supplicant/main_winsvc.c b/wpa_supplicant/main_winsvc.c
index 4a46ed5..0b7d5ce 100644
--- a/wpa_supplicant/main_winsvc.c
+++ b/wpa_supplicant/main_winsvc.c
@@ -2,14 +2,8 @@
* WPA Supplicant / main() function for Win32 service
* Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* The root of wpa_supplicant configuration in registry is
* HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
diff --git a/wpa_supplicant/nfc_pw_token.c b/wpa_supplicant/nfc_pw_token.c
new file mode 100644
index 0000000..11afb5b
--- /dev/null
+++ b/wpa_supplicant/nfc_pw_token.c
@@ -0,0 +1,83 @@
+/*
+ * nfc_pw_token - Tool for building NFC password tokens for WPS
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "crypto/random.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "wps_supplicant.h"
+
+
+static void print_bin(const char *title, const struct wpabuf *buf)
+{
+ size_t i, len;
+ const u8 *pos;
+
+ if (buf == NULL)
+ return;
+
+ printf("%s=", title);
+
+ pos = wpabuf_head(buf);
+ len = wpabuf_len(buf);
+ for (i = 0; i < len; i++)
+ printf("%02X", *pos++);
+
+ printf("\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct wpa_supplicant wpa_s;
+ int ret = -1;
+ struct wpabuf *buf = NULL, *ndef = NULL;
+ char txt[1000];
+
+ if (os_program_init())
+ return -1;
+ random_init(NULL);
+
+ os_memset(&wpa_s, 0, sizeof(wpa_s));
+ wpa_s.conf = os_zalloc(sizeof(*wpa_s.conf));
+ if (wpa_s.conf == NULL)
+ goto fail;
+
+ buf = wpas_wps_nfc_token(&wpa_s, 0);
+ if (buf == NULL)
+ goto fail;
+
+ ndef = ndef_build_wifi(buf);
+ if (ndef == NULL)
+ goto fail;
+
+ wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(buf),
+ wpabuf_len(buf));
+ printf("#WPS=%s\n", txt);
+
+ wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(ndef),
+ wpabuf_len(ndef));
+ printf("#NDEF=%s\n", txt);
+
+ printf("wps_nfc_dev_pw_id=%d\n", wpa_s.conf->wps_nfc_dev_pw_id);
+ print_bin("wps_nfc_dh_pubkey", wpa_s.conf->wps_nfc_dh_pubkey);
+ print_bin("wps_nfc_dh_privkey", wpa_s.conf->wps_nfc_dh_privkey);
+ print_bin("wps_nfc_dev_pw", wpa_s.conf->wps_nfc_dev_pw);
+
+ ret = 0;
+fail:
+ wpabuf_free(ndef);
+ wpabuf_free(buf);
+ wpa_config_free(wpa_s.conf);
+ random_deinit();
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 136d25f..a82fbf3 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -2,14 +2,8 @@
* wpa_supplicant - Event notifications
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -96,13 +90,23 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
#ifdef ANDROID
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
- "id=%d state=%d BSSID=" MACSTR,
+ "id=%d state=%d BSSID=" MACSTR " SSID=%s",
wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
- new_state, MAC2STR(wpa_s->pending_bssid));
+ new_state,
+ MAC2STR(wpa_s->bssid),
+ wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
+ wpa_ssid_txt(wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len) : "");
#endif /* ANDROID */
}
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+}
+
+
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
@@ -222,7 +226,7 @@ void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
* applications since these network objects won't behave like
* regular ones.
*/
- if (wpa_s->global->p2p_group_formation != wpa_s)
+ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_register_network(wpa_s, ssid);
}
@@ -250,7 +254,7 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
{
if (wpa_s->wpa)
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- if (wpa_s->global->p2p_group_formation != wpa_s)
+ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_unregister_network(wpa_s, ssid->id);
#ifdef CONFIG_P2P
wpas_p2p_network_removed(wpa_s, ssid);
@@ -323,6 +327,9 @@ void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+#ifdef CONFIG_WPS
+ wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
+#endif /* CONFIG_WPS */
}
@@ -544,6 +551,9 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
*/
wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
#endif /* CONFIG_P2P */
+
+ /* Notify listeners a new station has been authorized */
+ wpas_dbus_signal_sta_authorized(wpa_s, sta);
}
@@ -563,6 +573,9 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
*/
wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
#endif /* CONFIG_P2P */
+
+ /* Notify listeners a station has been deauthorized */
+ wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
}
@@ -608,3 +621,23 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
/* notify the new DBus API */
wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
}
+
+
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+#ifdef CONFIG_AP
+ wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal);
+#endif /* CONFIG_AP */
+}
+
+
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+ const char *parameter)
+{
+ wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_EAP_STATUS
+ "status='%s' parameter='%s'",
+ status, parameter);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 236a31e..58675ac 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -2,14 +2,8 @@
* wpa_supplicant - Event notifications
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef NOTIFY_H
@@ -28,6 +22,7 @@ void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
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_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);
@@ -127,5 +122,10 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
const char *subject, const char *cert_hash,
const struct wpabuf *cert);
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+ const char *parameter);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 790f14a..40cbea1 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -3,14 +3,8 @@
* Copyright (c) 2009-2010, Atheros Communications
* Copyright (c) 2011, Qualcomm Atheros
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -138,6 +132,17 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
}
+/**
+ * offchannel_send_action_tx_status - TX status callback
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dst: Destination MAC address of the transmitted Action frame
+ * @data: Transmitted frame payload
+ * @data_len: Length of @data in bytes
+ * @result: TX status
+ *
+ * This function is called whenever the driver indicates a TX status event for
+ * a frame sent by offchannel_send_action() using wpa_drv_send_action().
+ */
void offchannel_send_action_tx_status(
struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
size_t data_len, enum offchannel_send_action_result result)
@@ -154,6 +159,21 @@ void offchannel_send_action_tx_status(
return;
}
+ /* Accept report only if the contents of the frame matches */
+ if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 ||
+ os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx),
+ wpabuf_len(wpa_s->pending_action_tx)) != 0) {
+ wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+ "mismatching contents with pending frame");
+ wpa_hexdump(MSG_MSGDUMP, "TX status frame data",
+ data, data_len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
+
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
@@ -170,6 +190,27 @@ void offchannel_send_action_tx_status(
}
+/**
+ * offchannel_send_action - Request off-channel Action frame TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: The frequency in MHz indicating the channel on which the frame is to
+ * transmitted or 0 for the current channel (only if associated)
+ * @dst: Action frame destination MAC address
+ * @src: Action frame source MAC address
+ * @bssid: Action frame BSSID
+ * @buf: Frame to transmit starting from the Category field
+ * @len: Length of @buf in bytes
+ * @wait_time: Wait time for response in milliseconds
+ * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @no_cck: Whether CCK rates are to be disallowed for TX rate selection
+ * Returns: 0 on success or -1 on failure
+ *
+ * This function is used to request an Action frame to be transmitted on the
+ * current operating channel or on another channel (off-channel). The actual
+ * frame transmission will be delayed until the driver is ready on the specified
+ * channel. The @wait_time parameter can be used to request the driver to remain
+ * awake on the channel to wait for a response.
+ */
int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
const u8 *dst, const u8 *src, const u8 *bssid,
const u8 *buf, size_t len, unsigned int wait_time,
@@ -259,6 +300,8 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
"channel");
if (wait_time > wpa_s->max_remain_on_chan)
wait_time = wpa_s->max_remain_on_chan;
+ else if (wait_time == 0)
+ wait_time = 20;
if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
"to remain on channel (%u MHz) for Action "
@@ -272,6 +315,13 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
}
+/**
+ * offchannel_send_send_action_done - Notify completion of Action frame sequence
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function can be used to cancel a wait for additional response frames on
+ * the channel that was used with offchannel_send_action().
+ */
void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
@@ -290,6 +340,15 @@ void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
}
+/**
+ * offchannel_remain_on_channel_cb - Remain-on-channel callback function
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency (in MHz) of the selected channel
+ * @duration: Duration of the remain-on-channel operation in milliseconds
+ *
+ * This function is called whenever the driver notifies beginning of a
+ * remain-on-channel operation.
+ */
void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration)
{
@@ -299,6 +358,14 @@ void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
}
+/**
+ * offchannel_cancel_remain_on_channel_cb - Remain-on-channel stopped callback
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency (in MHz) of the selected channel
+ *
+ * This function is called whenever the driver notifies termination of a
+ * remain-on-channel operation.
+ */
void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
@@ -306,9 +373,42 @@ void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
}
-void offchannel_deinit(struct wpa_supplicant *wpa_s)
+/**
+ * offchannel_pending_action_tx - Check whether there is a pending Action TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to pending frame or %NULL if no pending operation
+ *
+ * This function can be used to check whether there is a pending Action frame TX
+ * operation. The returned pointer should be used only for checking whether it
+ * is %NULL (no pending frame) or to print the pointer value in debug
+ * information (i.e., the pointer should not be dereferenced).
+ */
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->pending_action_tx;
+}
+
+
+/**
+ * offchannel_clear_pending_action_tx - Clear pending Action frame TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
+}
+
+
+/**
+ * offchannel_deinit - Deinit off-channel operations
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to free up any allocated resources for off-channel
+ * operations.
+ */
+void offchannel_deinit(struct wpa_supplicant *wpa_s)
+{
+ offchannel_clear_pending_action_tx(wpa_s);
eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
}
diff --git a/wpa_supplicant/offchannel.h b/wpa_supplicant/offchannel.h
index 60e0d03..0ad7e18 100644
--- a/wpa_supplicant/offchannel.h
+++ b/wpa_supplicant/offchannel.h
@@ -3,14 +3,8 @@
* Copyright (c) 2009-2010, Atheros Communications
* Copyright (c) 2011, Qualcomm Atheros
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef OFFCHANNEL_H
@@ -35,5 +29,7 @@ void offchannel_deinit(struct wpa_supplicant *wpa_s);
void offchannel_send_action_tx_status(
struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
size_t data_len, enum offchannel_send_action_result result);
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s);
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s);
#endif /* OFFCHANNEL_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index c2b1521..2928b6f 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1,15 +1,10 @@
/*
* wpa_supplicant - P2P
* Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -23,6 +18,9 @@
#include "p2p/p2p.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
+#include "ap/sta_info.h"
+#include "ap/ap_drv_ops.h"
+#include "ap/wps_hostapd.h"
#include "ap/p2p_hostapd.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
@@ -37,6 +35,7 @@
#include "offchannel.h"
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
/*
@@ -45,6 +44,8 @@
*/
#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+#define P2P_AUTO_PD_SCAN_ATTEMPTS 5
+
#ifndef P2P_MAX_CLIENT_IDLE
/*
* How many seconds to try to reconnect to the GO when connection in P2P client
@@ -53,21 +54,146 @@
#define P2P_MAX_CLIENT_IDLE 10
#endif /* P2P_MAX_CLIENT_IDLE */
+#ifndef P2P_MAX_INITIAL_CONN_WAIT
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step on the GO. This controls the extra time the P2P
+ * operation is considered to be in progress (e.g., to delay other scans) after
+ * WPS provisioning has been completed on the GO during group formation.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
+
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * re-invocation of a persistent group on the GO when the client is expected
+ * to connect automatically (no user interaction).
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
+
+#ifndef P2P_CONCURRENT_SEARCH_DELAY
+#define P2P_CONCURRENT_SEARCH_DELAY 500
+#endif /* P2P_CONCURRENT_SEARCH_DELAY */
+
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
+enum p2p_group_removal_reason {
+ P2P_GROUP_REMOVAL_UNKNOWN,
+ P2P_GROUP_REMOVAL_SILENT,
+ P2P_GROUP_REMOVAL_FORMATION_FAILED,
+ P2P_GROUP_REMOVAL_REQUESTED,
+ P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
+ P2P_GROUP_REMOVAL_UNAVAILABLE,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
+ P2P_GROUP_REMOVAL_PSK_FAILURE,
+ P2P_GROUP_REMOVAL_FREQ_CONFLICT
+};
+
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
static struct wpa_supplicant *
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);
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len);
+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);
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
- const u8 *dev_addr, enum p2p_wps_method wps_method);
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
- void *timeout_ctx);
+ const u8 *dev_addr, enum p2p_wps_method wps_method,
+ int auto_join, int freq,
+ const u8 *ssid, size_t ssid_len);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added);
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+
+
+/*
+ * Get the number of concurrent channels that the HW can operate, but that are
+ * currently not in use by any of the wpa_supplicant interfaces.
+ */
+static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
+{
+ int *freqs;
+ int num, unused;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ os_free(freqs);
+
+ unused = wpa_s->num_multichan_concurrent - num;
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: num_unused_channels: %d", unused);
+ return unused;
+}
+
+
+/*
+ * Get the frequencies that are currently in use by one or more of the virtual
+ * interfaces, and that are also valid for P2P operation.
+ */
+static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
+ int *p2p_freqs, unsigned int len)
+{
+ int *freqs;
+ unsigned int num, i, j;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ os_memset(p2p_freqs, 0, sizeof(int) * len);
+
+ for (i = 0, j = 0; i < num && j < len; i++) {
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+ p2p_freqs[j++] = freqs[i];
+ }
+
+ os_free(freqs);
+
+ dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+
+ return j;
+}
+
+
+static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+ if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+ freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration",
+ freq);
+ freq = 0;
+ }
+ p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
+}
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -75,6 +201,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
{
size_t i;
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
@@ -83,10 +215,29 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
+ struct os_reltime time_tmp_age, entry_ts;
+ const u8 *ies;
+ size_t ies_len;
+
+ time_tmp_age.sec = bss->age / 1000;
+ time_tmp_age.usec = (bss->age % 1000) * 1000;
+ os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
+
+ ies = (const u8 *) (bss + 1);
+ ies_len = bss->ie_len;
+ if (bss->beacon_ie_len > 0 &&
+ !wpa_scan_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ wpa_scan_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ wpa_printf(MSG_DEBUG, "P2P: Use P2P IE(s) from Beacon frame since no P2P IE(s) in Probe Response frames received for "
+ MACSTR, MAC2STR(bss->bssid));
+ ies = ies + ies_len;
+ ies_len = bss->beacon_ie_len;
+ }
+
+
if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
- bss->freq, bss->level,
- (const u8 *) (bss + 1),
- bss->ie_len) > 0)
+ bss->freq, &entry_ts, bss->level,
+ ies, ies_len) > 0)
break;
}
@@ -94,80 +245,125 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_driver_scan_params *params = work->ctx;
+ int ret;
+
+ if (deinit) {
+ wpa_scan_free_params(params);
+ return;
+ }
+
+ ret = wpa_drv_scan(wpa_s, params);
+ wpa_scan_free_params(params);
+ work->ctx = NULL;
+ if (ret) {
+ radio_work_done(work);
+ return;
+ }
+
+ os_get_reltime(&wpa_s->scan_trigger_time);
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ wpa_s->own_scan_requested = 1;
+ wpa_s->p2p_scan_work = work;
+}
+
+
static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
- const u8 *req_dev_types, const u8 *dev_id)
+ const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
- struct wpa_driver_scan_params params;
- int ret;
+ struct wpa_driver_scan_params *params = NULL;
struct wpabuf *wps_ie, *ies;
- int social_channels[] = { 2412, 2437, 2462, 0, 0 };
size_t ielen;
+ u8 *n;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- os_memset(&params, 0, sizeof(params));
+ if (wpa_s->p2p_scan_work) {
+ wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending");
+ return -1;
+ }
+
+ params = os_zalloc(sizeof(*params));
+ if (params == NULL)
+ return -1;
/* P2P Wildcard SSID */
- params.num_ssids = 1;
- params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
- params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ params->num_ssids = 1;
+ n = os_malloc(P2P_WILDCARD_SSID_LEN);
+ if (n == NULL)
+ goto fail;
+ os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+ params->ssids[0].ssid = n;
+ params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE,
+ wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+ wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
num_req_dev_types, req_dev_types);
if (wps_ie == NULL)
- return -1;
+ 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);
- return -1;
+ 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;
- params.extra_ies = wpabuf_head(ies);
- params.extra_ies_len = wpabuf_len(ies);
+ 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 = social_channels;
+ params->freqs = os_malloc(4 * sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ params->freqs[0] = 2412;
+ params->freqs[1] = 2437;
+ params->freqs[2] = 2462;
+ params->freqs[3] = 0;
break;
case P2P_SCAN_FULL:
break;
- case P2P_SCAN_SPECIFIC:
- social_channels[0] = freq;
- social_channels[1] = 0;
- params.freqs = social_channels;
- break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
- social_channels[3] = freq;
- params.freqs = social_channels;
+ params->freqs = os_malloc(5 * sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ params->freqs[0] = 2412;
+ params->freqs[1] = 2437;
+ params->freqs[2] = 2462;
+ params->freqs[3] = freq;
+ params->freqs[4] = 0;
break;
}
- ret = wpa_drv_scan(wpa_s, &params);
-
- wpabuf_free(ies);
-
- if (ret) {
- if (wpa_s->scanning ||
- wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
- wpa_s->p2p_cb_on_scan_complete = 1;
- ret = 1;
- }
- } else
- wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ radio_remove_unstarted_work(wpa_s, "p2p-scan");
+ if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
+ params) < 0)
+ goto fail;
+ return 0;
- return ret;
+fail:
+ wpa_scan_free_params(params);
+ return -1;
}
@@ -211,7 +407,8 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
}
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
+ enum p2p_group_removal_reason removal_reason)
{
struct wpa_ssid *ssid;
char *gtype;
@@ -221,16 +418,22 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
if (ssid == NULL) {
/*
* The current SSID was not known, but there may still be a
- * pending P2P group interface waiting for provisioning.
+ * pending P2P group interface waiting for provisioning or a
+ * P2P group that is trying to reconnect.
*/
ssid = wpa_s->conf->ssid;
while (ssid) {
- if (ssid->p2p_group &&
- (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
- (ssid->key_mgmt & WPA_KEY_MGMT_WPS)))
+ if (ssid->p2p_group && ssid->disabled != 2)
break;
ssid = ssid->next;
}
+ if (ssid == NULL &&
+ wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)
+ {
+ wpa_printf(MSG_ERROR, "P2P: P2P group interface "
+ "not found");
+ return -1;
+ }
}
if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO)
gtype = "GO";
@@ -245,30 +448,60 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
gtype = "GO";
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
- wpa_s->ifname, wpa_s->cross_connect_uplink);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
}
- switch (wpa_s->removal_reason) {
+ switch (removal_reason) {
case P2P_GROUP_REMOVAL_REQUESTED:
reason = " reason=REQUESTED";
break;
+ case P2P_GROUP_REMOVAL_FORMATION_FAILED:
+ reason = " reason=FORMATION_FAILED";
+ break;
case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
reason = " reason=IDLE";
break;
case P2P_GROUP_REMOVAL_UNAVAILABLE:
reason = " reason=UNAVAILABLE";
break;
+ case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
+ reason = " reason=GO_ENDING_SESSION";
+ break;
+ case P2P_GROUP_REMOVAL_PSK_FAILURE:
+ reason = " reason=PSK_FAILURE";
+ break;
+ case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
+ reason = " reason=FREQ_CONFLICT";
+ break;
default:
reason = "";
break;
}
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
- wpa_s->ifname, gtype, reason);
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_REMOVED "%s %s%s",
+ wpa_s->ifname, gtype, reason);
+ }
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+ if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict timeout");
+ 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_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
+ "timeout");
+ wpa_s->p2p_in_provisioning = 0;
+ }
- if (ssid)
+ /*
+ * Make sure wait for the first client does not remain active after the
+ * group has been removed.
+ */
+ wpa_s->global->p2p_go_wait_client.sec = 0;
+
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -280,14 +513,25 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
global = wpa_s->global;
ifname = os_strdup(wpa_s->ifname);
type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
- wpa_supplicant_remove_iface(wpa_s->global, wpa_s);
+ wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
wpa_s = global->ifaces;
if (wpa_s && ifname)
wpa_drv_if_remove(wpa_s, type, ifname);
os_free(ifname);
- return;
+ return 1;
+ }
+
+ if (!wpa_s->p2p_go_group_formation_completed) {
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
}
+ wpa_s->show_group_started = 0;
+ os_free(wpa_s->go_params);
+ wpa_s->go_params = NULL;
+
+ wpa_s->waiting_presence_resp = 0;
+
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
if (ssid && (ssid->p2p_group ||
ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
@@ -318,6 +562,8 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
else
wpa_drv_deinit_p2p_cli(wpa_s);
+
+ return 0;
}
@@ -337,6 +583,10 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
bssid = wpa_s->bssid;
bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+ if (bss == NULL && wpa_s->go_params &&
+ !is_zero_ether_addr(wpa_s->go_params->peer_device_addr))
+ bss = wpa_bss_get_p2p_dev_addr(
+ wpa_s, wpa_s->go_params->peer_device_addr);
if (bss == NULL) {
u8 iface_addr[ETH_ALEN];
if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
@@ -351,6 +601,9 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
}
p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (p2p == NULL)
+ p2p = wpa_bss_get_vendor_ie_multi_beacon(bss,
+ P2P_IE_VENDOR_TYPE);
if (p2p == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
"group is persistent - BSS " MACSTR
@@ -457,6 +710,11 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s->ssid_len = ssid->ssid_len;
os_memcpy(s->ssid, ssid->ssid, s->ssid_len);
}
+ if (ssid->mode == WPAS_MODE_P2P_GO && wpa_s->global->add_psk) {
+ dl_list_add(&s->psk_list, &wpa_s->global->add_psk->list);
+ wpa_s->global->add_psk = NULL;
+ changed = 1;
+ }
#ifndef CONFIG_NO_CONFIG_WRITE
if (changed && wpa_s->conf->update_config &&
@@ -513,8 +771,8 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
}
if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
- n = os_realloc(s->p2p_client_list,
- (s->num_p2p_clients + 1) * ETH_ALEN);
+ n = os_realloc_array(s->p2p_client_list,
+ s->num_p2p_clients + 1, ETH_ALEN);
if (n == NULL)
return;
os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
@@ -556,17 +814,21 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
*/
if (wpa_s->global->p2p_group_formation)
wpa_s = wpa_s->global->p2p_group_formation;
- wpa_s->global->p2p_group_formation = NULL;
- wpa_s->p2p_in_provisioning = 0;
+ if (wpa_s->p2p_go_group_formation_completed) {
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ }
if (!success) {
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_FORMATION_FAILURE);
- wpas_p2p_group_delete(wpa_s);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE);
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_FORMATION_FAILED);
return;
}
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_SUCCESS);
ssid = wpa_s->current_ssid;
if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
@@ -606,22 +868,23 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
} else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
char psk[65];
wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
- "%s",
- wpa_s->ifname, ssid_txt, ssid->frequency, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+ wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr="
+ MACSTR "%s",
+ wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+ MAC2STR(go_dev_addr),
+ persistent ? " [PERSISTENT]" : "");
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
} else {
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt, ssid ? ssid->frequency : 0,
- ssid && ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+ wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+ "go_dev_addr=" MACSTR "%s",
+ wpa_s->ifname, ssid_txt,
+ ssid ? ssid->frequency : 0,
+ ssid && ssid->passphrase ? ssid->passphrase : "",
+ MAC2STR(go_dev_addr),
+ persistent ? " [PERSISTENT]" : "");
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
}
@@ -629,10 +892,42 @@ 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);
+ 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)
+ if (!client) {
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ os_get_reltime(&wpa_s->global->p2p_go_wait_client);
+ }
+}
+
+
+struct send_action_work {
+ unsigned int freq;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ size_t len;
+ unsigned int wait_time;
+ u8 buf[0];
+};
+
+
+static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (!wpa_s->p2p_send_action_work)
+ 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;
}
@@ -646,10 +941,31 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
{
enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
+ if (wpa_s->p2p_send_action_work) {
+ struct send_action_work *awork;
+ awork = wpa_s->p2p_send_action_work->ctx;
+ if (awork->wait_time == 0) {
+ os_free(awork);
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+ } else {
+ /*
+ * In theory, this should not be needed, but number of
+ * places in the P2P code is still using non-zero wait
+ * time for the last Action frame in the sequence and
+ * some of these do not call send_action_done().
+ */
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 0, awork->wait_time * 1000,
+ wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ }
+ }
+
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
switch (result) {
case OFFCHANNEL_SEND_ACTION_SUCCESS:
@@ -668,13 +984,70 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
wpa_s->pending_pd_before_join &&
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
- os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+ os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+ wpa_s->p2p_fallback_to_go_neg) {
wpa_s->pending_pd_before_join = 0;
- wpa_printf(MSG_DEBUG, "P2P: Starting pending "
- "join-existing-group operation (no ACK for PD "
- "Req)");
- wpas_p2p_join_start(wpa_s);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+ "during p2p_connect-auto");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
+}
+
+
+static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct send_action_work *awork = work->ctx;
+
+ if (deinit) {
+ os_free(awork);
+ return;
+ }
+
+ if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src,
+ awork->bssid, awork->buf, awork->len,
+ awork->wait_time,
+ wpas_p2p_send_action_tx_status, 1) < 0) {
+ os_free(awork);
+ radio_work_done(work);
+ return;
}
+ wpa_s->p2p_send_action_work = work;
+}
+
+
+static int wpas_send_action_work(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid, const u8 *buf,
+ size_t len, unsigned int wait_time)
+{
+ struct send_action_work *awork;
+
+ if (wpa_s->p2p_send_action_work) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending");
+ return -1;
+ }
+
+ awork = os_zalloc(sizeof(*awork) + len);
+ if (awork == NULL)
+ return -1;
+
+ awork->freq = freq;
+ os_memcpy(awork->dst, dst, ETH_ALEN);
+ os_memcpy(awork->src, src, ETH_ALEN);
+ os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ awork->len = len;
+ awork->wait_time = wait_time;
+ os_memcpy(awork->buf, buf, len);
+
+ if (radio_add_work(wpa_s, freq, "p2p-send-action", 0,
+ wpas_send_action_cb, awork) < 0) {
+ os_free(awork);
+ return -1;
+ }
+
+ return 0;
}
@@ -683,6 +1056,20 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
size_t len, unsigned int wait_time)
{
struct wpa_supplicant *wpa_s = ctx;
+ int listen_freq = -1, send_freq = -1;
+
+ if (wpa_s->p2p_listen_work)
+ listen_freq = wpa_s->p2p_listen_work->freq;
+ if (wpa_s->p2p_send_action_work)
+ send_freq = wpa_s->p2p_send_action_work->freq;
+ if (listen_freq != (int) freq && send_freq != (int) freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)",
+ listen_freq, send_freq);
+ return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
+ len, wait_time);
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
wait_time,
wpas_p2p_send_action_tx_status, 1);
@@ -692,6 +1079,15 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
static void wpas_send_action_done(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->p2p_send_action_work) {
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ 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;
+ }
+
offchannel_send_action_done(wpa_s);
}
@@ -712,15 +1108,29 @@ static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
- wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
- MAC2STR(res->peer_interface_addr));
+ wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
+ " dev_addr " MACSTR " wps_method %d",
+ MAC2STR(res->peer_interface_addr),
+ MAC2STR(res->peer_device_addr), res->wps_method);
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
res->ssid, res->ssid_len);
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
- if (res->wps_method == WPS_PBC)
+ if (res->wps_method == WPS_PBC) {
wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
- else {
+#ifdef CONFIG_WPS_NFC
+ } 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 ==
+ DEV_PW_NFC_CONNECTION_HANDOVER ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash :
+ NULL,
+ NULL, 0, 0);
+#endif /* CONFIG_WPS_NFC */
+ } else {
u16 dev_pw_id = DEV_PW_DEFAULT;
if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
@@ -730,6 +1140,44 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_ssid *persistent;
+ struct psk_list_entry *psk;
+ struct hostapd_data *hapd;
+
+ if (!wpa_s->ap_iface)
+ return;
+
+ persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+ ssid->ssid_len);
+ if (persistent == NULL)
+ return;
+
+ hapd = wpa_s->ap_iface->bss[0];
+
+ dl_list_for_each(psk, &persistent->psk_list, struct psk_list_entry,
+ list) {
+ struct hostapd_wpa_psk *hpsk;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add persistent group PSK entry for "
+ MACSTR " psk=%d",
+ MAC2STR(psk->addr), psk->p2p);
+ hpsk = os_zalloc(sizeof(*hpsk));
+ if (hpsk == NULL)
+ break;
+ os_memcpy(hpsk->psk, psk->psk, PMK_LEN);
+ if (psk->p2p)
+ os_memcpy(hpsk->p2p_dev_addr, psk->addr, ETH_ALEN);
+ else
+ os_memcpy(hpsk->addr, psk->addr, ETH_ALEN);
+ hpsk->next = hapd->conf->ssid.wpa_psk;
+ hapd->conf->ssid.wpa_psk = hpsk;
+ }
+}
+
+
static void p2p_go_configured(void *ctx, void *data)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -742,25 +1190,60 @@ static void p2p_go_configured(void *ctx, void *data)
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
if (wpa_s->global->p2p_group_formation == wpa_s)
wpa_s->global->p2p_group_formation = NULL;
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->frequency,
- params->passphrase ? params->passphrase : "",
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ? " [PERSISTENT]" : "");
-
- if (params->persistent_group)
+ if (os_strlen(params->passphrase) > 0) {
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_STARTED
+ "%s GO ssid=\"%s\" freq=%d "
+ "passphrase=\"%s\" go_dev_addr=" MACSTR
+ "%s", wpa_s->ifname,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->frequency, params->passphrase,
+ MAC2STR(wpa_s->global->p2p_dev_addr),
+ params->persistent_group ?
+ " [PERSISTENT]" : "");
+ } else {
+ char psk[65];
+ wpa_snprintf_hex(psk, sizeof(psk), params->psk,
+ sizeof(params->psk));
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_STARTED
+ "%s GO ssid=\"%s\" freq=%d psk=%s "
+ "go_dev_addr=" MACSTR "%s",
+ wpa_s->ifname,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->frequency, psk,
+ MAC2STR(wpa_s->global->p2p_dev_addr),
+ params->persistent_group ?
+ " [PERSISTENT]" : "");
+ }
+
+ 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,
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_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
+
+ if (wpa_s->p2p_first_connection_timeout) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Start group formation timeout of %d seconds until first data connection on GO",
+ wpa_s->p2p_first_connection_timeout);
+ 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);
+ eloop_register_timeout(
+ wpa_s->p2p_first_connection_timeout, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+
return;
}
@@ -771,12 +1254,26 @@ static void p2p_go_configured(void *ctx, void *data)
"filtering");
return;
}
- if (params->wps_method == WPS_PBC)
+ if (params->wps_method == WPS_PBC) {
wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
params->peer_device_addr);
- else if (wpa_s->p2p_pin[0])
+#ifdef CONFIG_WPS_NFC
+ } else if (params->wps_method == WPS_NFC) {
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->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);
+#endif /* CONFIG_WPS_NFC */
+ } else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
- wpa_s->p2p_pin, NULL, 0);
+ wpa_s->p2p_pin, NULL, 0, 0);
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
}
@@ -788,12 +1285,18 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
{
struct wpa_ssid *ssid;
- if (wpas_copy_go_neg_results(wpa_s, params) < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Starting GO");
+ if (wpas_copy_go_neg_results(wpa_s, params) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not copy GO Negotiation "
+ "results");
return;
+ }
ssid = wpa_config_add_network(wpa_s->conf);
- if (ssid == NULL)
+ if (ssid == NULL) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO");
return;
+ }
wpa_s->show_group_started = 0;
@@ -804,6 +1307,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
+ ssid->ht40 = params->ht40;
+ ssid->vht = params->vht;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -813,7 +1318,22 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->passphrase = os_strdup(params->passphrase);
+ if (os_strlen(params->passphrase) > 0) {
+ ssid->passphrase = os_strdup(params->passphrase);
+ if (ssid->passphrase == NULL) {
+ wpa_msg_global(wpa_s, MSG_ERROR,
+ "P2P: Failed to copy passphrase for GO");
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return;
+ }
+ } else
+ ssid->passphrase = NULL;
+ ssid->psk_set = params->psk_set;
+ if (ssid->psk_set)
+ 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;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
@@ -821,6 +1341,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
wpa_s->connect_without_scan = ssid;
wpa_s->reassociate = 1;
wpa_s->disconnected = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Request scan (that will be skipped) to "
+ "start GO)");
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -852,6 +1374,36 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d->p2p_intra_bss = s->p2p_intra_bss;
d->persistent_reconnect = s->persistent_reconnect;
d->max_num_sta = s->max_num_sta;
+ d->pbc_in_m1 = s->pbc_in_m1;
+ d->ignore_old_scan_res = s->ignore_old_scan_res;
+ d->beacon_int = s->beacon_int;
+ d->dtim_period = s->dtim_period;
+ d->disassoc_low_ack = s->disassoc_low_ack;
+ d->disable_scan_offload = s->disable_scan_offload;
+
+ if (s->wps_nfc_dh_privkey && s->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);
+ }
+}
+
+
+static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
+ char *ifname, size_t len)
+{
+ char *ifname_ptr = wpa_s->ifname;
+
+ if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX,
+ os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1;
+ }
+
+ os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
+ if (os_strlen(ifname) >= IFNAMSIZ &&
+ os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+ /* Try to avoid going over the IFNAMSIZ length limit */
+ os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+ }
}
@@ -872,14 +1424,7 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
return 0;
}
- os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
- wpa_s->p2p_group_idx);
- if (os_strlen(ifname) >= IFNAMSIZ &&
- os_strlen(wpa_s->ifname) < IFNAMSIZ) {
- /* Try to avoid going over the IFNAMSIZ length limit */
- os_snprintf(ifname, sizeof(ifname), "p2p-%d",
- wpa_s->p2p_group_idx);
- }
+ wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname));
force_ifname[0] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
@@ -949,7 +1494,13 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
os_memset(&iface, 0, sizeof(iface));
iface.ifname = wpa_s->pending_interface_name;
iface.driver = wpa_s->driver->name;
- iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+ if (wpa_s->conf->ctrl_interface == NULL &&
+ wpa_s->parent != wpa_s &&
+ wpa_s->p2p_mgmt &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE))
+ iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface;
+ else
+ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
iface.driver_param = wpa_s->conf->driver_param;
group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
if (group_wpa_s == NULL) {
@@ -974,15 +1525,44 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
+ wpas_p2p_group_formation_failed(wpa_s);
+}
+
+
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
- else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- wpa_drv_p2p_group_formation_failed(wpa_s);
wpas_group_formation_completed(wpa_s, 0);
}
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+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);
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ wpa_s->global->p2p_fail_on_wps_complete = 0;
+}
+
+
+void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->global->p2p_group_formation != wpa_s)
+ return;
+ /* Speed up group formation timeout since this cannot succeed */
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+}
+
+
+static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -993,16 +1573,42 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
}
if (res->status) {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
- res->status);
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_GO_NEG_FAILURE "status=%d",
+ res->status);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
}
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+ if (wpa_s->p2p_go_ht40)
+ res->ht40 = 1;
+ if (wpa_s->p2p_go_vht)
+ res->vht = 1;
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
+ "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
+ " wps_method=%s",
+ res->role_go ? "GO" : "client", res->freq, res->ht40,
+ MAC2STR(res->peer_device_addr),
+ MAC2STR(res->peer_interface_addr),
+ p2p_wps_method_text(res->wps_method));
wpas_notify_p2p_go_neg_completed(wpa_s, res);
+ if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
+ struct wpa_ssid *ssid;
+ ssid = wpa_config_get_network(wpa_s->conf,
+ wpa_s->p2p_persistent_id);
+ if (ssid && ssid->disabled == 2 &&
+ ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
+ size_t len = os_strlen(ssid->passphrase);
+ wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
+ "on requested persistent group");
+ os_memcpy(res->passphrase, ssid->passphrase, len);
+ res->passphrase[len] = '\0';
+ }
+ }
+
if (wpa_s->create_p2p_iface) {
struct wpa_supplicant *group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go);
@@ -1043,32 +1649,44 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
}
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
- " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+ " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
}
-void wpas_dev_found(void *ctx, const u8 *addr,
- const struct p2p_peer_info *info,
- int new_device)
+static void wpas_dev_found(void *ctx, const u8 *addr,
+ const struct p2p_peer_info *info,
+ int new_device)
{
+#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
-
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
- " p2p_dev_addr=" MACSTR
- " pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x",
- MAC2STR(addr), MAC2STR(info->p2p_device_addr),
- wps_dev_type_bin2str(info->pri_dev_type, devtype,
- sizeof(devtype)),
- info->device_name, info->config_methods,
- info->dev_capab, info->group_capab);
+ char *wfd_dev_info_hex = NULL;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+ WFD_SUBELEM_DEVICE_INFO);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
+ " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s' config_methods=0x%x "
+ "dev_capab=0x%x group_capab=0x%x%s%s",
+ MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+ wps_dev_type_bin2str(info->pri_dev_type, devtype,
+ sizeof(devtype)),
+ info->device_name, info->config_methods,
+ info->dev_capab, info->group_capab,
+ wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
+ wfd_dev_info_hex ? wfd_dev_info_hex : "");
+
+ os_free(wfd_dev_info_hex);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
}
@@ -1078,39 +1696,118 @@ static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
- "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
+ "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
wpas_notify_p2p_device_lost(wpa_s, dev_addr);
}
-static int wpas_start_listen(void *ctx, unsigned int freq,
- unsigned int duration,
- const struct wpabuf *probe_resp_ie)
+static void wpas_find_stopped(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+}
- wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
+
+struct wpas_p2p_listen_work {
+ unsigned int freq;
+ unsigned int duration;
+ struct wpabuf *probe_resp_ie;
+};
+
+
+static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork)
+{
+ if (lwork == NULL)
+ return;
+ wpabuf_free(lwork->probe_resp_ie);
+ os_free(lwork);
+}
+
+
+static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_p2p_listen_work *lwork;
+
+ if (!wpa_s->p2p_listen_work)
+ return;
+
+ lwork = wpa_s->p2p_listen_work->ctx;
+ wpas_p2p_listen_work_free(lwork);
+ radio_work_done(wpa_s->p2p_listen_work);
+ wpa_s->p2p_listen_work = NULL;
+}
+
+
+static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpas_p2p_listen_work *lwork = work->ctx;
+
+ if (deinit) {
+ wpas_p2p_listen_work_free(lwork);
+ return;
+ }
+
+ wpa_s->p2p_listen_work = work;
+
+ wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL);
if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
"report received Probe Request frames");
- return -1;
+ wpas_p2p_listen_work_done(wpa_s);
+ return;
}
- wpa_s->pending_listen_freq = freq;
- wpa_s->pending_listen_duration = duration;
+ wpa_s->pending_listen_freq = lwork->freq;
+ wpa_s->pending_listen_duration = lwork->duration;
- if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
+ {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
- "state", freq);
+ "state", lwork->freq);
+ wpas_p2p_listen_work_done(wpa_s);
wpa_s->pending_listen_freq = 0;
- return -1;
+ return;
}
wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = freq;
+ wpa_s->roc_waiting_drv_freq = lwork->freq;
+}
+
+
+static int wpas_start_listen(void *ctx, unsigned int freq,
+ unsigned int duration,
+ const struct wpabuf *probe_resp_ie)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpas_p2p_listen_work *lwork;
+
+ if (wpa_s->p2p_listen_work) {
+ wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists");
+ return -1;
+ }
+
+ lwork = os_zalloc(sizeof(*lwork));
+ if (lwork == NULL)
+ return -1;
+ lwork->freq = freq;
+ lwork->duration = duration;
+ if (probe_resp_ie) {
+ lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie);
+ if (lwork->probe_resp_ie == NULL) {
+ wpas_p2p_listen_work_free(lwork);
+ return -1;
+ }
+ }
+
+ if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb,
+ lwork) < 0) {
+ wpas_p2p_listen_work_free(lwork);
+ return -1;
+ }
return 0;
}
@@ -1126,13 +1823,143 @@ static void wpas_stop_listen(void *ctx)
}
wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
wpa_drv_probe_req_report(wpa_s, 0);
+ wpas_p2p_listen_work_done(wpa_s);
}
static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
+ return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
+}
+
+
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+ u8 **spos, const u8 *end)
+{
+ while (*spos < end) {
+ u8 val = ((*spos)[0] & 0xc0) >> 6;
+ int len;
+
+ if (val == 1 || val == 2) {
+ /* These are reserved values in RFC 1035 */
+ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+ "sequence starting with 0x%x", val);
+ return -1;
+ }
+
+ if (val == 3) {
+ u16 offset;
+ u8 *spos_tmp;
+
+ /* Offset */
+ if (*spos + 2 > end) {
+ wpa_printf(MSG_DEBUG, "P2P: No room for full "
+ "DNS offset field");
+ return -1;
+ }
+
+ offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+ if (offset >= *spos - start) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+ "pointer offset %u", offset);
+ return -1;
+ }
+
+ (*spos) += 2;
+ spos_tmp = start + offset;
+ return p2p_sd_dns_uncompress_label(upos, uend, start,
+ &spos_tmp,
+ *spos - 2);
+ }
+
+ /* Label */
+ len = (*spos)[0] & 0x3f;
+ if (len == 0)
+ return 0;
+
+ (*spos)++;
+ if (*spos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+ "sequence - no room for label with length "
+ "%u", len);
+ return -1;
+ }
+
+ if (*upos + len + 2 > uend)
+ return -2;
+
+ os_memcpy(*upos, *spos, len);
+ *spos += len;
+ *upos += len;
+ (*upos)[0] = '.';
+ (*upos)++;
+ (*upos)[0] = '\0';
+ }
+
+ return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+ size_t msg_len, size_t offset)
+{
+ /* 27-octet in-memory packet from P2P specification */
+ const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+ "\x04_udp\xC0\x11\x00\x0C\x00\x01";
+ u8 *tmp, *end, *spos;
+ char *upos, *uend;
+ int ret = 0;
+
+ if (buf_len < 2)
+ return -1;
+ if (offset > msg_len)
+ return -1;
+
+ tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+ if (tmp == NULL)
+ return -1;
+ spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+ end = spos + msg_len;
+ spos += offset;
+
+ os_memset(tmp, 0, DNS_HEADER_LEN);
+ os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+ os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+ upos = buf;
+ uend = buf + buf_len;
+
+ ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+ if (ret) {
+ os_free(tmp);
+ return ret;
+ }
+
+ if (upos == buf) {
+ upos[0] = '.';
+ upos[1] = '\0';
+ } else if (upos[-1] == '.')
+ upos[-1] = '\0';
+
+ os_free(tmp);
+ return 0;
}
@@ -1226,13 +2053,40 @@ static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
}
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+ size_t query_len)
+{
+ char str_rx[256], str_srv[256];
+
+ if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+ return 0; /* Too short to include DNS Type and Version */
+ if (os_memcmp(query + query_len - 3,
+ wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+ 3) != 0)
+ return 0; /* Mismatch in DNS Type or Version */
+ if (query_len == wpabuf_len(bsrv->query) &&
+ os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+ return 1; /* Binary match */
+
+ if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+ 0))
+ return 0; /* Failed to uncompress query */
+ if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+ wpabuf_head(bsrv->query),
+ wpabuf_len(bsrv->query) - 3, 0))
+ return 0; /* Failed to uncompress service */
+
+ return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *resp, u8 srv_trans_id,
const u8 *query, size_t query_len)
{
struct p2p_srv_bonjour *bsrv;
- struct wpabuf buf;
u8 *len_pos;
+ int matches = 0;
wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
query, query_len);
@@ -1248,39 +2102,52 @@ static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
return;
}
- if (wpabuf_tailroom(resp) < 5)
- return;
- /* Length (to be filled) */
- len_pos = wpabuf_put(resp, 2);
- wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
- wpabuf_put_u8(resp, srv_trans_id);
+ dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+ struct p2p_srv_bonjour, list) {
+ if (!match_bonjour_query(bsrv, query, query_len))
+ continue;
+
+ if (wpabuf_tailroom(resp) <
+ 5 + query_len + wpabuf_len(bsrv->resp))
+ return;
+
+ matches++;
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+ wpabuf_put_u8(resp, srv_trans_id);
+
+ /* Status Code */
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+ wpabuf_head(bsrv->resp),
+ wpabuf_len(bsrv->resp));
+
+ /* Response Data */
+ wpabuf_put_data(resp, query, query_len); /* Key */
+ wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+ }
- wpabuf_set(&buf, query, query_len);
- bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
- if (bsrv == NULL) {
+ if (matches == 0) {
wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
"available");
+ if (wpabuf_tailroom(resp) < 5)
+ return;
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+ wpabuf_put_u8(resp, srv_trans_id);
/* Status Code */
wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
/* Response Data: empty */
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
2);
- return;
- }
-
- /* Status Code */
- wpabuf_put_u8(resp, P2P_SD_SUCCESS);
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
- wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp));
-
- if (wpabuf_tailroom(resp) >=
- wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) {
- /* Response Data */
- wpabuf_put_buf(resp, bsrv->query); /* Key */
- wpabuf_put_buf(resp, bsrv->resp); /* Value */
}
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
}
@@ -1401,8 +2268,64 @@ static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
}
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
- u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+#ifdef CONFIG_WIFI_DISPLAY
+static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
+ struct wpabuf *resp, u8 srv_trans_id,
+ const u8 *query, size_t query_len)
+{
+ const u8 *pos;
+ u8 role;
+ u8 *len_pos;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
+
+ if (!wpa_s->global->wifi_display) {
+ wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
+ wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
+ srv_trans_id);
+ return;
+ }
+
+ if (query_len < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
+ "Role");
+ return;
+ }
+
+ if (wpabuf_tailroom(resp) < 5)
+ return;
+
+ pos = query;
+ role = *pos++;
+ wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
+
+ /* TODO: role specific handling */
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
+ wpabuf_put_u8(resp, srv_trans_id);
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
+
+ while (pos < query + query_len) {
+ if (*pos < MAX_WFD_SUBELEMS &&
+ wpa_s->global->wfd_subelem[*pos] &&
+ wpabuf_tailroom(resp) >=
+ wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
+ wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
+ "subelement %u", *pos);
+ wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
+ }
+ pos++;
+ }
+
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+ u16 update_indic, const u8 *tlvs, size_t tlvs_len)
{
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos = tlvs;
@@ -1492,6 +2415,12 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
pos, tlv_end - pos);
break;
+#ifdef CONFIG_WIFI_DISPLAY
+ case P2P_SERV_WIFI_DISPLAY:
+ wpas_sd_req_wfd(wpa_s, resp, srv_trans_id,
+ pos, tlv_end - pos);
+ break;
+#endif /* CONFIG_WIFI_DISPLAY */
default:
wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
"protocol %u", srv_proto);
@@ -1513,8 +2442,8 @@ done:
}
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
+static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
{
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos = tlvs;
@@ -1578,26 +2507,24 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
}
-void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
- const struct wpabuf *tlvs)
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return (void *) wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
- return NULL;
- return p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
+ return 0;
+ return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
}
-void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
- u8 version, const char *query)
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+ u8 version, const char *query)
{
struct wpabuf *tlvs;
- void *ret;
+ u64 ret;
tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
if (tlvs == NULL)
- return NULL;
+ return 0;
wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
@@ -1609,13 +2536,92 @@ void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
}
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req)
+#ifdef CONFIG_WIFI_DISPLAY
+
+static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *tlvs)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return 0;
+ return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+#define MAX_WFD_SD_SUBELEMS 20
+
+static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
+ const char *subelems)
+{
+ u8 *len;
+ const char *pos;
+ int val;
+ int count = 0;
+
+ len = wpabuf_put(tlvs, 2);
+ wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
+ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+
+ wpabuf_put_u8(tlvs, role);
+
+ pos = subelems;
+ while (*pos) {
+ val = atoi(pos);
+ if (val >= 0 && val < 256) {
+ wpabuf_put_u8(tlvs, val);
+ count++;
+ if (count == MAX_WFD_SD_SUBELEMS)
+ break;
+ }
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
+}
+
+
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *role)
+{
+ struct wpabuf *tlvs;
+ u64 ret;
+ const char *subelems;
+ u8 id = 1;
+
+ subelems = os_strchr(role, ' ');
+ if (subelems == NULL)
+ return 0;
+ subelems++;
+
+ tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
+ if (tlvs == NULL)
+ return 0;
+
+ if (os_strstr(role, "[source]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
+ if (os_strstr(role, "[pri-sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
+ if (os_strstr(role, "[sec-sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
+ if (os_strstr(role, "[source+sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
+
+ ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+ return ret;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_sd_cancel_request(wpa_s, (u64) req);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- return p2p_sd_cancel_request(wpa_s->global->p2p, req);
+ return p2p_sd_cancel_request(wpa_s->global->p2p,
+ (void *) (uintptr_t) req);
}
@@ -1623,11 +2629,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
const u8 *dst, u8 dialog_token,
const struct wpabuf *resp_tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
- resp_tlvs);
- return;
- }
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
@@ -1637,10 +2638,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_service_update(wpa_s);
- return;
- }
if (wpa_s->global->p2p)
p2p_sd_service_update(wpa_s->global->p2p);
}
@@ -1685,14 +2682,6 @@ int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
{
struct p2p_srv_bonjour *bsrv;
- bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
- if (bsrv) {
- wpabuf_free(query);
- wpabuf_free(bsrv->resp);
- bsrv->resp = resp;
- return 0;
- }
-
bsrv = os_zalloc(sizeof(*bsrv));
if (bsrv == NULL)
return -1;
@@ -1760,24 +2749,24 @@ static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
const u8 *peer, const char *params,
unsigned int generated_pin)
{
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s",
- MAC2STR(peer), generated_pin, params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR
+ " %08d%s", MAC2STR(peer), generated_pin, params);
}
static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s,
const u8 *peer, const char *params)
{
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR "%s",
- MAC2STR(peer), params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR
+ "%s", MAC2STR(peer), params);
}
-void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
- const u8 *dev_addr, const u8 *pri_dev_type,
- const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab, const u8 *group_id,
- size_t group_id_len)
+static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+ const u8 *dev_addr, const u8 *pri_dev_type,
+ const char *dev_name, u16 supp_config_methods,
+ u8 dev_capab, u8 group_capab, const u8 *group_id,
+ size_t group_id_len)
{
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -1821,8 +2810,8 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
} else if (config_methods & WPS_CONFIG_KEYPAD)
wpas_prov_disc_local_keypad(wpa_s, peer, params);
else if (config_methods & WPS_CONFIG_PUSHBUTTON)
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
- "%s", MAC2STR(peer), params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ
+ MACSTR "%s", MAC2STR(peer), params);
wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
P2P_PROV_DISC_SUCCESS,
@@ -1830,10 +2819,11 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
}
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
{
struct wpa_supplicant *wpa_s = ctx;
unsigned int generated_pin = 0;
+ char params[20];
if (wpa_s->pending_pd_before_join &&
(os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
@@ -1841,18 +2831,26 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
wpa_s->pending_pd_before_join = 0;
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation");
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
return;
}
+ if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
+ wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
+ os_snprintf(params, sizeof(params), " peer_go=%d",
+ wpa_s->pending_pd_use == AUTO_PD_JOIN);
+ else
+ params[0] = '\0';
+
if (config_methods & WPS_CONFIG_DISPLAY)
- wpas_prov_disc_local_keypad(wpa_s, peer, "");
+ wpas_prov_disc_local_keypad(wpa_s, peer, params);
else if (config_methods & WPS_CONFIG_KEYPAD) {
generated_pin = wps_generate_pin();
- wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
+ wpas_prov_disc_local_display(wpa_s, peer, params,
+ generated_pin);
} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
- MAC2STR(peer));
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP
+ MACSTR "%s", MAC2STR(peer), params);
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
P2P_PROV_DISC_SUCCESS,
@@ -1860,30 +2858,61 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
}
-void wpas_prov_disc_fail(void *ctx, const u8 *peer,
- enum p2p_prov_disc_status status)
+static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+ enum p2p_prov_disc_status status)
{
struct wpa_supplicant *wpa_s = ctx;
+ 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");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
+
+ if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
+ wpa_s->pending_pd_before_join = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+ "join-existing-group operation (no ACK for PD "
+ "Req attempts)");
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
+ return;
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d",
+ MAC2STR(peer), status);
+
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
status, 0, 0);
}
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+ if (channels == NULL)
+ return 1; /* Assume no restrictions */
+ return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group)
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels,
+ int dev_pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
- u8 cur_bssid[ETH_ALEN];
int res;
struct wpa_supplicant *grp;
if (!persistent_group) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
- " to join an active group", MAC2STR(sa));
+ " to join an active group (SSID: %s)",
+ MAC2STR(sa), wpa_ssid_txt(ssid, ssid_len));
if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
(os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
== 0 ||
@@ -1892,6 +2921,21 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
"authorized invitation");
goto accept_inv;
}
+
+#ifdef CONFIG_WPS_NFC
+ if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled &&
+ dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) {
+ wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
+ wpa_s->parent->p2p_wps_method = WPS_NFC;
+ wpa_s->parent->pending_join_wps_method = WPS_NFC;
+ os_memcpy(wpa_s->parent->pending_join_dev_addr,
+ go_dev_addr, ETH_ALEN);
+ os_memcpy(wpa_s->parent->pending_join_iface_addr,
+ bssid, ETH_ALEN);
+ goto accept_inv;
+ }
+#endif /* CONFIG_WPS_NFC */
+
/*
* Do not accept the invitation automatically; notify user and
* request approval.
@@ -1908,7 +2952,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
goto accept_inv;
}
- if (!wpa_s->conf->persistent_reconnect)
+ if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+ os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
+ "invitation to re-invoke a persistent group");
+ } else if (!wpa_s->conf->persistent_reconnect)
return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
for (s = wpa_s->conf->ssid; s; s = s->next) {
@@ -1948,19 +2996,37 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
}
accept_inv:
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
- wpa_s->assoc_freq) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
- "the channel we are already using");
- *force_freq = wpa_s->assoc_freq;
+ wpas_p2p_set_own_freq_preference(wpa_s, 0);
+
+ /* Get one of the frequencies currently in use */
+ if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
+ wpas_p2p_set_own_freq_preference(wpa_s, res);
+
+ if (wpa_s->num_multichan_concurrent < 2 ||
+ wpas_p2p_num_unused_channels(wpa_s) < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
+ *force_freq = res;
+ }
}
- res = wpa_drv_shared_freq(wpa_s);
- if (res > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
- "with the channel we are already using on a "
- "shared interface");
- *force_freq = res;
+ if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ if (*go == 0) {
+ /* We are the client */
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+ "running a GO but we are capable of MCC, "
+ "figure out the best channel to use");
+ *force_freq = 0;
+ } else if (!freq_included(channels, *force_freq)) {
+ /* We are the GO, and *force_freq is not in the
+ * intersection */
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "in intersection but we are capable of MCC, "
+ "figure out the best channel to use",
+ *force_freq);
+ *force_freq = 0;
+ }
}
return P2P_SC_SUCCESS;
@@ -1984,14 +3050,18 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (status == P2P_SC_SUCCESS) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
- " was accepted; op_freq=%d MHz",
- MAC2STR(sa), op_freq);
+ " was accepted; op_freq=%d MHz, SSID=%s",
+ MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
+ int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
+ wpa_s, s, go, go ? op_freq : 0, 0, 0, NULL,
+ go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
} else if (bssid) {
+ wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
- wpa_s->p2p_wps_method);
+ wpa_s->p2p_wps_method, 0, op_freq,
+ ssid, ssid_len);
}
return;
}
@@ -2004,44 +3074,132 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (!s) {
if (bssid) {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
- "sa=" MACSTR " go_dev_addr=" MACSTR
- " bssid=" MACSTR " unknown-network",
- MAC2STR(sa), MAC2STR(go_dev_addr),
- MAC2STR(bssid));
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " bssid=" MACSTR " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr),
+ MAC2STR(bssid));
} else {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
- "sa=" MACSTR " go_dev_addr=" MACSTR
- " unknown-network",
- MAC2STR(sa), MAC2STR(go_dev_addr));
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr));
}
return;
}
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR
- " persistent=%d", MAC2STR(sa), s->id);
+ if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " persistent=%d freq=%d",
+ MAC2STR(sa), s->id, op_freq);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " persistent=%d",
+ MAC2STR(sa), s->id);
+ }
}
-static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
+static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *peer, int inv)
+{
+ size_t i;
+
+ if (ssid == NULL)
+ return;
+
+ for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
+ if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
+ ETH_ALEN) == 0)
+ break;
+ }
+ if (i >= ssid->num_p2p_clients) {
+ if (ssid->mode != WPAS_MODE_P2P_GO &&
+ os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d "
+ "due to invitation result", ssid->id);
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return;
+ }
+ return; /* Peer not found in client list */
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
+ "group %d client list%s",
+ MAC2STR(peer), ssid->id,
+ inv ? " due to invitation result" : "");
+ os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
+ ssid->p2p_client_list + (i + 1) * ETH_ALEN,
+ (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
+ ssid->num_p2p_clients--;
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->parent->conf->update_config &&
+ wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
+static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
+ const u8 *peer)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_s = wpa_s->global->p2p_invite_group;
+ if (wpa_s == NULL)
+ return; /* No known invitation group */
+ ssid = wpa_s->current_ssid;
+ 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->ssid, ssid->ssid_len);
+ wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
+}
+
+
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
+ const struct p2p_channels *channels,
+ const u8 *peer, int neg_freq)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
+ int freq;
if (bssid) {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
- "status=%d " MACSTR,
- status, MAC2STR(bssid));
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+ "status=%d " MACSTR,
+ status, MAC2STR(bssid));
} else {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
- "status=%d ", status);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+ "status=%d ", status);
}
wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
- if (wpa_s->pending_invite_ssid_id == -1)
+ wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
+ status, MAC2STR(peer));
+ if (wpa_s->pending_invite_ssid_id == -1) {
+ if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
+ wpas_remove_persistent_client(wpa_s, peer);
return; /* Invitation to active group */
+ }
+
+ if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+ wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another "
+ "invitation exchange to indicate readiness for "
+ "re-invocation");
+ }
if (status != P2P_SC_SUCCESS) {
+ if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
+ ssid = wpa_config_get_network(
+ wpa_s->conf, wpa_s->pending_invite_ssid_id);
+ wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
+ }
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
}
@@ -2054,49 +3212,107 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
return;
}
+ /*
+ * The peer could have missed our ctrl::ack frame for Invitation
+ * Response and continue retransmitting the frame. To reduce the
+ * likelihood of the peer not getting successful TX status for the
+ * Invitation Response frame, wait a short time here before starting
+ * the persistent group so that we will remain on the current channel to
+ * acknowledge any possible retransmission from the peer.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before "
+ "starting persistent group");
+ os_sleep(0, 50000);
+
+ freq = wpa_s->p2p_persistent_go_freq;
+ if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO &&
+ freq_included(channels, neg_freq)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use frequence %d MHz from invitation for GO mode",
+ neg_freq);
+ freq = neg_freq;
+ }
+
wpas_p2p_group_add_persistent(wpa_s, ssid,
- ssid->mode == WPAS_MODE_P2P_GO, 0);
+ ssid->mode == WPAS_MODE_P2P_GO,
+ freq,
+ wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+ channels,
+ ssid->mode == WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+ 0);
+}
+
+
+static int wpas_p2p_disallowed_freq(struct wpa_global *global,
+ unsigned int freq)
+{
+ if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq))
+ return 1;
+ return freq_range_list_includes(&global->p2p_disallow_freq, freq);
+}
+
+
+static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
+{
+ reg->channel[reg->channels] = chan;
+ reg->channels++;
}
static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
- struct p2p_channels *chan)
+ struct p2p_channels *chan,
+ struct p2p_channels *cli_chan)
{
int i, cla = 0;
+ os_memset(cli_chan, 0, sizeof(*cli_chan));
+
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
"band");
/* Operating class 81 - 2.4 GHz band channels 1..13 */
chan->reg_class[cla].reg_class = 81;
- chan->reg_class[cla].channels = 11;
- for (i = 0; i < 11; i++)
- chan->reg_class[cla].channel[i] = i + 1;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ for (i = 0; i < 11; i++) {
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], i + 1);
+ }
+ if (chan->reg_class[cla].channels)
+ cla++;
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
"band");
/* Operating class 115 - 5 GHz, channels 36-48 */
chan->reg_class[cla].reg_class = 115;
- chan->reg_class[cla].channels = 4;
- chan->reg_class[cla].channel[0] = 36;
- chan->reg_class[cla].channel[1] = 40;
- chan->reg_class[cla].channel[2] = 44;
- chan->reg_class[cla].channel[3] = 48;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 36);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 40);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 44);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 48);
+ if (chan->reg_class[cla].channels)
+ cla++;
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
"band");
/* Operating class 124 - 5 GHz, channels 149,153,157,161 */
chan->reg_class[cla].reg_class = 124;
- chan->reg_class[cla].channels = 4;
- chan->reg_class[cla].channel[0] = 149;
- chan->reg_class[cla].channel[1] = 153;
- chan->reg_class[cla].channel[2] = 157;
- chan->reg_class[cla].channel[3] = 161;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 149);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 153);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 157);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 161);
+ if (chan->reg_class[cla].channels)
+ cla++;
chan->reg_classes = cla;
return 0;
@@ -2118,23 +3334,38 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
}
-static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
+enum chan_allowed {
+ NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+};
+
+static int has_channel(struct wpa_global *global,
+ struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
int i;
+ unsigned int freq;
+
+ freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
+ chan * 5;
+ if (wpas_p2p_disallowed_freq(global, freq))
+ return NOT_ALLOWED;
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].chan == chan) {
if (flags)
*flags = mode->channels[i].flag;
- return !(mode->channels[i].flag &
- (HOSTAPD_CHAN_DISABLED |
- HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_RADAR));
+ if (mode->channels[i].flag &
+ (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ return NOT_ALLOWED;
+ if (mode->channels[i].flag &
+ (HOSTAPD_CHAN_PASSIVE_SCAN |
+ HOSTAPD_CHAN_NO_IBSS))
+ return PASSIVE_ONLY;
+ return ALLOWED;
}
}
- return 0;
+ return NOT_ALLOWED;
}
@@ -2144,80 +3375,224 @@ struct p2p_oper_class_map {
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
+};
+
+static 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, 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 },
+ { -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;
+
+ 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 wpas_p2p_verify_80mhz(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_80mhz(wpa_s, mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+ if (center_chan >= 58 && center_chan <= 138)
+ return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
+
+ /* check all the channels are available */
+ for (i = 0; i < 4; i++) {
+ int adj_chan = center_chan - 6 + i * 4;
+
+ res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+ if (res == NOT_ALLOWED)
+ return NOT_ALLOWED;
+ if (res == PASSIVE_ONLY)
+ ret = PASSIVE_ONLY;
+
+ if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_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)
+{
+ int flag;
+ enum chan_allowed res, res2;
+
+ res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+ if (bw == BW40MINUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+ return NOT_ALLOWED;
+ res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+ } else if (bw == BW40PLUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+ return NOT_ALLOWED;
+ res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+ } else if (bw == BW80) {
+ res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+ }
+
+ if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+ return NOT_ALLOWED;
+ if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
+ return PASSIVE_ONLY;
+ return res;
+}
+
+
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
- struct p2p_channels *chan)
+ struct p2p_channels *chan,
+ struct p2p_channels *cli_chan)
{
struct hostapd_hw_modes *mode;
- int cla, op;
- 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, 116, 36, 44, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
- { -1, 0, 0, 0, 0, BW20 }
- };
+ int cla, op, cli_cla;
if (wpa_s->hw.modes == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
"of all supported channels; assume dualband "
"support");
- return wpas_p2p_default_channels(wpa_s, chan);
+ return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
}
- cla = 0;
+ cla = cli_cla = 0;
for (op = 0; op_class[op].op_class; op++) {
struct p2p_oper_class_map *o = &op_class[op];
u8 ch;
- struct p2p_reg_class *reg = NULL;
+ struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- int flag;
- if (!has_channel(mode, ch, &flag))
- continue;
- if (o->bw == BW40MINUS &&
- (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(mode, ch - 4, NULL)))
- continue;
- if (o->bw == BW40PLUS &&
- (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(mode, ch + 4, NULL)))
- continue;
- if (reg == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Add operating "
- "class %u", o->op_class);
- reg = &chan->reg_class[cla];
- cla++;
- reg->reg_class = o->op_class;
+ enum chan_allowed res;
+ res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ if (res == ALLOWED) {
+ if (reg == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
+ o->op_class);
+ reg = &chan->reg_class[cla];
+ cla++;
+ reg->reg_class = o->op_class;
+ }
+ reg->channel[reg->channels] = ch;
+ reg->channels++;
+ } else if (res == PASSIVE_ONLY &&
+ wpa_s->conf->p2p_add_cli_chan) {
+ if (cli_reg == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
+ o->op_class);
+ cli_reg = &cli_chan->reg_class[cli_cla];
+ cli_cla++;
+ cli_reg->reg_class = o->op_class;
+ }
+ cli_reg->channel[cli_reg->channels] = ch;
+ cli_reg->channels++;
}
- reg->channel[reg->channels] = ch;
- reg->channels++;
}
if (reg) {
wpa_hexdump(MSG_DEBUG, "P2P: Channels",
reg->channel, reg->channels);
}
+ if (cli_reg) {
+ wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
+ cli_reg->channel, cli_reg->channels);
+ }
}
chan->reg_classes = cla;
+ cli_chan->reg_classes = cli_cla;
return 0;
}
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ int op;
+ enum chan_allowed ret;
+
+ for (op = 0; op_class[op].op_class; op++) {
+ struct p2p_oper_class_map *o = &op_class[op];
+ u8 ch;
+
+ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+ if (o->mode != HOSTAPD_MODE_IEEE80211A ||
+ o->bw == BW20 || ch != channel)
+ continue;
+ ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ if (ret == ALLOWED)
+ return (o->bw == BW40MINUS) ? -1 : 1;
+ }
+ }
+ return 0;
+}
+
+
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+ return 0;
+
+ return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -2255,6 +3630,89 @@ static int wpas_go_connected(void *ctx, const u8 *dev_addr)
}
+static int wpas_is_concurrent_session_active(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *ifs;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s)
+ continue;
+ if (ifs->wpa_state > WPA_ASSOCIATED)
+ return 1;
+ }
+ return 0;
+}
+
+
+static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_msg_global(wpa_s, level, "P2P: %s", msg);
+}
+
+
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_interface iface;
+ struct wpa_supplicant *p2pdev_wpa_s;
+ char ifname[100];
+ char force_name[100];
+ int ret;
+
+ os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+ wpa_s->ifname);
+ force_name[0] = '\0';
+ wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
+ ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+ force_name, wpa_s->pending_interface_addr, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
+ return ret;
+ }
+ os_strlcpy(wpa_s->pending_interface_name, ifname,
+ sizeof(wpa_s->pending_interface_name));
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.p2p_mgmt = 1;
+ iface.ifname = wpa_s->pending_interface_name;
+ iface.driver = wpa_s->driver->name;
+ iface.driver_param = wpa_s->conf->driver_param;
+ iface.confname = wpa_s->confname;
+ p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ if (!p2pdev_wpa_s) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
+ return -1;
+ }
+ p2pdev_wpa_s->parent = wpa_s;
+
+ wpa_s->pending_interface_name[0] = '\0';
+ return 0;
+}
+
+
+static void wpas_presence_resp(void *ctx, const u8 *src, u8 status,
+ const u8 *noa, size_t noa_len)
+{
+ struct wpa_supplicant *wpa_s, *intf = ctx;
+ char hex[100];
+
+ for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_s->waiting_presence_resp)
+ break;
+ }
+ if (!wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response");
+ return;
+ }
+ wpa_s->waiting_presence_resp = 0;
+
+ wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len);
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR
+ " status=%u noa=%s", MAC2STR(src), status, hex);
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
@@ -2267,34 +3725,18 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
unsigned int r;
int i;
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+ if (wpa_s->conf->p2p_disabled)
return 0;
- if (global->p2p)
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
return 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- struct p2p_params params;
-
- wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
- os_memset(&params, 0, sizeof(params));
- params.dev_name = wpa_s->conf->device_name;
- os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
- WPS_DEV_TYPE_LEN);
- params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
- os_memcpy(params.sec_dev_type,
- wpa_s->conf->sec_device_type,
- params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
-
- if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
- return -1;
-
+ if (global->p2p)
return 0;
- }
os_memset(&p2p, 0, sizeof(p2p));
- p2p.msg_ctx = wpa_s;
p2p.cb_ctx = wpa_s;
+ p2p.debug_print = wpas_p2p_debug_print;
p2p.p2p_scan = wpas_p2p_scan;
p2p.send_action = wpas_send_action;
p2p.send_action_done = wpas_send_action_done;
@@ -2302,6 +3744,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.go_neg_req_rx = wpas_go_neg_req_rx;
p2p.dev_found = wpas_dev_found;
p2p.dev_lost = wpas_dev_lost;
+ p2p.find_stopped = wpas_find_stopped;
p2p.start_listen = wpas_start_listen;
p2p.stop_listen = wpas_stop_listen;
p2p.send_probe_resp = wpas_send_probe_resp;
@@ -2315,6 +3758,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.invitation_result = wpas_invitation_result;
p2p.get_noa = wpas_get_noa;
p2p.go_connected = wpas_go_connected;
+ p2p.presence_resp = wpas_presence_resp;
+ p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -2363,13 +3808,19 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
"%d:%d", p2p.op_reg_class, p2p.op_channel);
}
+
+ if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {
+ p2p.pref_chan = wpa_s->conf->p2p_pref_chan;
+ p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;
+ }
+
if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
os_memcpy(p2p.country, wpa_s->conf->country, 2);
p2p.country[2] = 0x04;
} else
os_memcpy(p2p.country, "XX\x04", 3);
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
"channel list");
return -1;
@@ -2398,6 +3849,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+ p2p.max_listen = wpa_s->max_remain_on_chan;
+
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
@@ -2410,6 +3863,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
global->p2p, wpa_s->conf->wps_vendor_ext[i]);
}
+ p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
+
return 0;
}
@@ -2436,11 +3891,21 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
wpa_s->go_params = NULL;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ wpas_p2p_listen_work_done(wpa_s);
+ if (wpa_s->p2p_send_action_work) {
+ 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;
+ }
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
@@ -2457,17 +3922,17 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s, *tmp;
+ wpa_s = global->ifaces;
+ if (wpa_s)
+ wpas_p2p_service_flush(wpa_s);
+
if (global->p2p == NULL)
return;
/* Remove remaining P2P group interfaces */
- wpa_s = global->ifaces;
- if (wpa_s)
- wpas_p2p_service_flush(wpa_s);
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
wpa_s = wpa_s->next;
while (wpa_s) {
- enum wpa_driver_if_type type;
tmp = global->ifaces;
while (tmp &&
(tmp == wpa_s ||
@@ -2476,7 +3941,6 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
}
if (tmp == NULL)
break;
- type = wpas_p2p_if_type(tmp->p2p_group_interface);
/* Disconnect from the P2P group and deinit the interface */
wpas_p2p_disconnect(tmp);
}
@@ -2498,6 +3962,9 @@ 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)
+ return 0; /* separate interface disabled per configuration */
if (wpa_s->drv_flags &
(WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
@@ -2517,20 +3984,26 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ struct wpa_ssid *ssid, unsigned int pref_freq)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
- go_intent, own_interface_addr,
- force_freq, persistent_group);
- }
+ /*
+ * Increase GO config timeout if HT40 is used since it takes some time
+ * to scan channels for coex purposes before the BSS can be started.
+ */
+ p2p_set_config_timeout(wpa_s->global->p2p,
+ wpa_s->p2p_go_ht40 ? 255 : 100, 20);
return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
- persistent_group);
+ persistent_group, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0,
+ wpa_s->p2p_pd_before_go_neg, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
@@ -2538,17 +4011,18 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ struct wpa_ssid *ssid, unsigned int pref_freq)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
-
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
- persistent_group);
+ persistent_group, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
@@ -2562,31 +4036,87 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
" for join operationg - stop join attempt",
MAC2STR(wpa_s->pending_join_iface_addr));
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_FORMATION_FAILURE);
+ if (wpa_s->p2p_auto_pd) {
+ wpa_s->p2p_auto_pd = 0;
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ return;
+ }
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE);
}
}
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
+static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- if (!wpa_s->pending_pd_before_join)
- return;
- /*
- * Provision Discovery Response may have been lost - try to connect
- * anyway since we do not need any information from this PD.
- */
- wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
- "try to connect anyway");
- wpas_p2p_join_start(wpa_s);
+ int *freqs, res, num, i;
+
+ if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ /* Multiple channels are supported and not all are in use */
+ return 0;
+ }
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return 1;
+
+ num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ if (num < 0) {
+ res = 1;
+ goto exit_free;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (freqs[i] == freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
+ freq);
+ res = 0;
+ goto exit_free;
+ }
+ }
+
+ res = 1;
+
+exit_free:
+ os_free(freqs);
+ return res;
+}
+
+
+static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
+ const u8 *peer_dev_addr)
+{
+ struct wpa_bss *bss;
+ int updated;
+
+ bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
+ if (bss == NULL)
+ return -1;
+ if (bss->last_update_idx < wpa_s->bss_update_idx) {
+ wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
+ "last scan");
+ return 0;
+ }
+
+ updated = os_reltime_before(&wpa_s->p2p_auto_started,
+ &bss->last_update);
+ wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
+ "%ld.%06ld (%supdated in last scan)",
+ bss->last_update.sec, bss->last_update.usec,
+ updated ? "": "not ");
+
+ return updated;
}
static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss = NULL;
int freq;
u8 iface_addr[ETH_ALEN];
@@ -2595,12 +4125,79 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
if (wpa_s->global->p2p_disabled)
return;
- wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
- scan_res ? (int) scan_res->num : -1);
+ wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
+ scan_res ? (int) scan_res->num : -1,
+ wpa_s->p2p_auto_join ? "auto_" : "");
if (scan_res)
wpas_p2p_scan_res_handler(wpa_s, scan_res);
+ if (wpa_s->p2p_auto_pd) {
+ int join = wpas_p2p_peer_go(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (join == 0 &&
+ wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
+ wpa_s->auto_pd_scan_retry++;
+ bss = wpa_bss_get_bssid_latest(
+ wpa_s, wpa_s->pending_join_dev_addr);
+ if (bss) {
+ freq = bss->freq;
+ wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
+ "the peer " MACSTR " at %d MHz",
+ wpa_s->auto_pd_scan_retry,
+ MAC2STR(wpa_s->
+ pending_join_dev_addr),
+ freq);
+ wpas_p2p_join_scan_req(wpa_s, freq, NULL, 0);
+ return;
+ }
+ }
+
+ if (join < 0)
+ join = 0;
+
+ wpa_s->p2p_auto_pd = 0;
+ wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
+ wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
+ MAC2STR(wpa_s->pending_join_dev_addr), join);
+ if (p2p_prov_disc_req(wpa_s->global->p2p,
+ wpa_s->pending_join_dev_addr,
+ wpa_s->pending_pd_config_methods, join,
+ 0, wpa_s->user_initiated_pd) < 0) {
+ wpa_s->p2p_auto_pd = 0;
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ }
+ return;
+ }
+
+ if (wpa_s->p2p_auto_join) {
+ int join = wpas_p2p_peer_go(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (join < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
+ "running a GO -> use GO Negotiation");
+ wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
+ wpa_s->p2p_pin, wpa_s->p2p_wps_method,
+ wpa_s->p2p_persistent_group, 0, 0, 0,
+ wpa_s->p2p_go_intent,
+ wpa_s->p2p_connect_freq,
+ wpa_s->p2p_persistent_id,
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
+ "try to join the group", join ? "" :
+ " in older scan");
+ if (!join)
+ wpa_s->p2p_fallback_to_go_neg = 1;
+ }
+
freq = p2p_get_oper_freq(wpa_s->global->p2p,
wpa_s->pending_join_iface_addr);
if (freq < 0 &&
@@ -2624,15 +4221,38 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ if (wpa_s->p2p_join_ssid_len) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+ MACSTR " and SSID %s",
+ MAC2STR(wpa_s->pending_join_iface_addr),
+ wpa_ssid_txt(wpa_s->p2p_join_ssid,
+ wpa_s->p2p_join_ssid_len));
+ 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) {
+ 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,
+ wpa_s->pending_join_iface_addr);
+ }
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
- "from BSS table: %d MHz", freq);
+ "from BSS table: %d MHz (SSID %s)", freq,
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
}
if (freq > 0) {
u16 method;
+ if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE
+ "reason=FREQ_CONFLICT");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
"prior to joining an existing group (GO " MACSTR
" freq=%u MHz)",
@@ -2661,7 +4281,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
* We have already performed provision discovery for
* joining the group. Proceed directly to join
* operation without duplicated provision discovery. */
- wpa_printf(MSG_DEBUG, "P2P: Provisioning discovery "
+ wpa_printf(MSG_DEBUG, "P2P: Provision discovery "
"with " MACSTR " already done - proceed to "
"join",
MAC2STR(wpa_s->pending_join_dev_addr));
@@ -2671,25 +4291,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
if (p2p_prov_disc_req(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr, method, 1,
- freq) < 0) {
+ freq, wpa_s->user_initiated_pd) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
"existing group");
wpa_s->pending_pd_before_join = 0;
goto start;
}
-
- /*
- * Actual join operation will be started from the Action frame
- * TX status callback (if no ACK is received) or when the
- * Provision Discovery Response is received. Use a short
- * timeout as a backup mechanism should the Provision Discovery
- * Response be lost for any reason.
- */
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
- NULL);
- eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
- wpa_s, NULL);
return;
}
@@ -2701,28 +4309,38 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
start:
/* Start join operation immediately */
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
}
-static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
int ret;
struct wpa_driver_scan_params params;
struct wpabuf *wps_ie, *ies;
size_t ielen;
+ int freqs[2] = { 0, 0 };
os_memset(&params, 0, sizeof(params));
/* P2P Wildcard SSID */
params.num_ssids = 1;
- params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
- params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ if (ssid && ssid_len) {
+ params.ssids[0].ssid = ssid;
+ params.ssids[0].ssid_len = ssid_len;
+ os_memcpy(wpa_s->p2p_join_ssid, ssid, ssid_len);
+ wpa_s->p2p_join_ssid_len = ssid_len;
+ } else {
+ params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+ params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ wpa_s->p2p_join_ssid_len = 0;
+ }
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE, 0, NULL);
+ wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
+ wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
+ NULL);
if (wps_ie == NULL) {
wpas_p2p_scan_res_join(wpa_s, NULL);
return;
@@ -2744,12 +4362,32 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
+ if (!freq) {
+ int oper_freq;
+ /*
+ * If freq is not provided, check the operating freq of the GO
+ * and use a single channel scan on if possible.
+ */
+ oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
+ wpa_s->pending_join_iface_addr);
+ if (oper_freq > 0)
+ freq = oper_freq;
+ }
+ if (freq > 0) {
+ freqs[0] = freq;
+ params.freqs = freqs;
+ }
+
/*
* Run a scan to update BSS table and start Provision Discovery once
* the new scan results become available.
*/
- wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
ret = wpa_drv_scan(wpa_s, &params);
+ if (!ret) {
+ os_get_reltime(&wpa_s->scan_trigger_time);
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+ wpa_s->own_scan_requested = 1;
+ }
wpabuf_free(ies);
@@ -2763,13 +4401,29 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
}
+static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpas_p2p_join_scan_req(wpa_s, 0, NULL, 0);
+}
+
+
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
- const u8 *dev_addr, enum p2p_wps_method wps_method)
+ const u8 *dev_addr, enum p2p_wps_method wps_method,
+ int auto_join, int op_freq,
+ const u8 *ssid, size_t ssid_len)
{
wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
- MACSTR " dev " MACSTR ")",
- MAC2STR(iface_addr), MAC2STR(dev_addr));
+ MACSTR " dev " MACSTR " op_freq=%d)%s",
+ MAC2STR(iface_addr), MAC2STR(dev_addr), op_freq,
+ auto_join ? " (auto_join)" : "");
+ if (ssid && ssid_len) {
+ wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s",
+ wpa_ssid_txt(ssid, ssid_len));
+ }
+ wpa_s->p2p_auto_pd = 0;
+ wpa_s->p2p_auto_join = !!auto_join;
os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
wpa_s->pending_join_wps_method = wps_method;
@@ -2778,17 +4432,18 @@ static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
wpas_p2p_stop_find(wpa_s);
wpa_s->p2p_join_scan_count = 0;
- wpas_p2p_join_scan(wpa_s, NULL);
+ wpas_p2p_join_scan_req(wpa_s, op_freq, ssid, ssid_len);
return 0;
}
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len)
{
struct wpa_supplicant *group;
struct p2p_go_neg_results res;
+ struct wpa_bss *bss;
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
if (group == NULL)
return -1;
@@ -2796,14 +4451,42 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
sizeof(group->p2p_pin));
group->p2p_wps_method = wpa_s->p2p_wps_method;
+ } else {
+ /*
+ * Need to mark the current interface for p2p_group_formation
+ * when a separate group interface is not used. This is needed
+ * to allow p2p_cancel stop a pending p2p_connect-join.
+ * wpas_p2p_init_group_interface() addresses this for the case
+ * where a separate group interface is used.
+ */
+ wpa_s->global->p2p_group_formation = wpa_s;
}
group->p2p_in_provisioning = 1;
+ group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
os_memset(&res, 0, sizeof(res));
+ os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
res.wps_method = wpa_s->pending_join_wps_method;
+ if (freq && ssid && ssid_len) {
+ res.freq = 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 (bss) {
+ res.freq = bss->freq;
+ res.ssid_len = bss->ssid_len;
+ os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ 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));
+ }
+ }
+
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to "
"starting client");
@@ -2826,35 +4509,141 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
}
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+ int *force_freq, int *pref_freq, int go)
+{
+ int *freqs, res;
+ unsigned int freq_in_use = 0, num, i;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ wpa_printf(MSG_DEBUG,
+ "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
+ freq, wpa_s->num_multichan_concurrent, num);
+
+ if (freq > 0) {
+ int ret;
+ if (go)
+ ret = p2p_supported_freq(wpa_s->global->p2p, freq);
+ else
+ ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
+ if (!ret) {
+ wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+ "(%u MHz) is not supported for P2P uses",
+ freq);
+ res = -3;
+ goto exit_free;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (freqs[i] == freq)
+ freq_in_use = 1;
+ }
+
+ if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
+ freq);
+ res = -2;
+ goto exit_free;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+ "requested channel (%u MHz)", freq);
+ *force_freq = freq;
+ goto exit_ok;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+ continue;
+
+ if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
+ freqs[i]);
+ *pref_freq = freqs[i];
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
+ freqs[i]);
+ *force_freq = freqs[i];
+ }
+ break;
+ }
+
+ if (i == num) {
+ if (num < wpa_s->num_multichan_concurrent && num > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
+ *force_freq = 0;
+ } else if (num < wpa_s->num_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new channel");
+ *force_freq = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
+ res = -2;
+ goto exit_free;
+ }
+ }
+
+exit_ok:
+ res = 0;
+exit_free:
+ os_free(freqs);
+ return res;
+}
+
+
/**
* wpas_p2p_connect - Request P2P Group Formation to be started
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
* @peer_addr: Address of the peer P2P Device
* @pin: PIN to use during provisioning or %NULL to indicate PBC mode
* @persistent_group: Whether to create a persistent group
+ * @auto_join: Whether to select join vs. GO Negotiation automatically
* @join: Whether to join an existing group (as a client) instead of starting
* Group Owner negotiation; @peer_addr is BSSID in that case
* @auth: Whether to only authorize the connection instead of doing that and
* initiating Group Owner negotiation
* @go_intent: GO Intent or -1 to use default
* @freq: Frequency for the group or 0 for auto-selection
+ * @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
* 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
*/
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 join, int auth, int go_intent,
- int freq)
+ 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 force_freq = 0, oper_freq = 0;
- u8 bssid[ETH_ALEN];
- int ret = 0;
+ int force_freq = 0, pref_freq = 0;
+ int ret = 0, res;
enum wpa_driver_if_type iftype;
+ const u8 *if_addr;
+ struct wpa_ssid *ssid = NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (persistent_id >= 0) {
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+ if (ssid == NULL || ssid->disabled != 2 ||
+ ssid->mode != WPAS_MODE_P2P_GO)
+ return -1;
+ }
+
+ os_free(wpa_s->global->add_psk);
+ wpa_s->global->add_psk = NULL;
+
+ wpa_s->global->p2p_fail_on_wps_complete = 0;
+
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
@@ -2862,6 +4651,14 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
+ wpa_s->p2p_persistent_group = !!persistent_group;
+ wpa_s->p2p_persistent_id = persistent_id;
+ wpa_s->p2p_go_intent = go_intent;
+ wpa_s->p2p_connect_freq = freq;
+ wpa_s->p2p_fallback_to_go_neg = 0;
+ wpa_s->p2p_pd_before_go_neg = !!pd;
+ wpa_s->p2p_go_ht40 = !!ht40;
+ wpa_s->p2p_go_vht = !!vht;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -2874,7 +4671,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
} else
wpa_s->p2p_pin[0] = '\0';
- if (join) {
+ if (join || auto_join) {
u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
if (auth) {
wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
@@ -2890,100 +4687,58 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
dev_addr);
}
- if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
- 0)
+ if (auto_join) {
+ os_get_reltime(&wpa_s->p2p_auto_started);
+ wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
+ "%ld.%06ld",
+ wpa_s->p2p_auto_started.sec,
+ wpa_s->p2p_auto_started.usec);
+ }
+ wpa_s->user_initiated_pd = 1;
+ if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
+ auto_join, freq, NULL, 0) < 0)
return -1;
return ret;
}
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq)
- oper_freq = wpa_s->assoc_freq;
- else {
- oper_freq = wpa_drv_shared_freq(wpa_s);
- if (oper_freq < 0)
- oper_freq = 0;
- }
-
- if (freq > 0) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel "
- "(%u MHz) is not supported for P2P uses",
- freq);
- return -3;
- }
-
- if (oper_freq > 0 && freq != oper_freq &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "on %u MHz while connected on another "
- "channel (%u MHz)", freq, oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "requested channel (%u MHz)", freq);
- force_freq = freq;
- } else if (oper_freq > 0 &&
- !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
- if (!(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "while connected on non-P2P supported "
- "channel (%u MHz)", oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
- "(%u MHz) not available for P2P - try to use "
- "another channel", oper_freq);
- force_freq = 0;
- } else if (oper_freq > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "channel we are already using (%u MHz) on another "
- "interface", oper_freq);
- force_freq = oper_freq;
- }
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ go_intent == 15);
+ if (res)
+ return res;
+ wpas_p2p_set_own_freq_preference(wpa_s,
+ force_freq ? force_freq : pref_freq);
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
- if (!wpa_s->create_p2p_iface) {
- if (auth) {
- if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
- go_intent, wpa_s->own_addr,
- force_freq, persistent_group)
- < 0)
- return -1;
- return ret;
- }
- if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
- go_intent, wpa_s->own_addr,
- force_freq, persistent_group) < 0)
+ if (wpa_s->create_p2p_iface) {
+ /* Prepare to add a new interface for the group */
+ iftype = WPA_IF_P2P_GROUP;
+ if (go_intent == 15)
+ iftype = WPA_IF_P2P_GO;
+ if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+ "interface for the group");
return -1;
- return ret;
- }
+ }
- /* Prepare to add a new interface for the group */
- iftype = WPA_IF_P2P_GROUP;
- if (go_intent == 15)
- iftype = WPA_IF_P2P_GO;
- if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
- wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
- "interface for the group");
- return -1;
- }
+ if_addr = wpa_s->pending_interface_addr;
+ } else
+ if_addr = wpa_s->own_addr;
if (auth) {
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
- go_intent,
- wpa_s->pending_interface_addr,
- force_freq, persistent_group) < 0)
+ go_intent, if_addr,
+ force_freq, persistent_group, ssid,
+ pref_freq) < 0)
return -1;
return ret;
}
- if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent,
- wpa_s->pending_interface_addr,
- force_freq, persistent_group) < 0) {
- wpas_p2p_remove_pending_group_interface(wpa_s);
+
+ if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
+ go_intent, if_addr, force_freq,
+ persistent_group, ssid, pref_freq) < 0) {
+ if (wpa_s->create_p2p_iface)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
}
return ret;
@@ -3019,9 +4774,6 @@ static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
if (timeout > wpa_s->max_remain_on_chan)
timeout = wpa_s->max_remain_on_chan;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_listen(wpa_s, timeout);
-
return p2p_listen(wpa_s->global->p2p, timeout);
}
@@ -3040,18 +4792,25 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
+ wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
- if (wpa_s->pending_action_tx)
+ if (offchannel_pending_action_tx(wpa_s))
return;
if (wpa_s->p2p_long_listen > 0)
wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (wpa_s->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ } else {
+ /*
+ * When listen duration is over, stop listen & update p2p_state
+ * to IDLE.
+ */
+ p2p_stop_listen(wpa_s->global->p2p);
}
}
@@ -3079,7 +4838,11 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
while (wpa_s) {
prev = wpa_s;
wpa_s = wpa_s->next;
- wpas_p2p_disconnect(prev);
+ if (prev->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (prev->current_ssid &&
+ prev->current_ssid->p2p_group))
+ wpas_p2p_disconnect(prev);
}
return 0;
}
@@ -3093,78 +4856,187 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
}
+static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+ unsigned int r;
+
+ if (freq == 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+ "band");
+ if (wpa_s->best_24_freq > 0 &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_24_freq)) {
+ freq = wpa_s->best_24_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+ "channel: %d MHz", freq);
+ } else {
+ os_get_random((u8 *) &r, sizeof(r));
+ freq = 2412 + (r % 3) * 25;
+ wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+ "channel: %d MHz", freq);
+ }
+ }
+
+ if (freq == 5) {
+ wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+ "band");
+ if (wpa_s->best_5_freq > 0 &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_5_freq)) {
+ freq = wpa_s->best_5_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+ "channel: %d MHz", freq);
+ } else {
+ os_get_random((u8 *) &r, sizeof(r));
+ freq = 5180 + (r % 4) * 20;
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not select "
+ "5 GHz channel for P2P group");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+ "channel: %d MHz", freq);
+ }
+ }
+
+ if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+ "(%u MHz) is not supported for P2P uses",
+ freq);
+ return -1;
+ }
+
+ return freq;
+}
+
+
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq)
+ int freq, int ht40, int vht,
+ const struct p2p_channels *channels)
{
- u8 bssid[ETH_ALEN];
- int res;
+ int res, *freqs;
+ unsigned int pref_freq;
+ unsigned int num, i;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
+ params->ht40 = ht40;
+ params->vht = vht;
if (freq) {
+ if (!freq_included(channels, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "accepted", freq);
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
"frequency %d MHz", freq);
params->freq = freq;
} else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
wpa_s->conf->p2p_oper_channel >= 1 &&
- wpa_s->conf->p2p_oper_channel <= 11) {
+ wpa_s->conf->p2p_oper_channel <= 11 &&
+ freq_included(channels,
+ 2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
- } else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
- wpa_s->conf->p2p_oper_reg_class == 124) {
+ } else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
+ wpa_s->conf->p2p_oper_reg_class == 116 ||
+ wpa_s->conf->p2p_oper_reg_class == 117 ||
+ wpa_s->conf->p2p_oper_reg_class == 124 ||
+ wpa_s->conf->p2p_oper_reg_class == 126 ||
+ wpa_s->conf->p2p_oper_reg_class == 127) &&
+ freq_included(channels,
+ 5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_overall_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_overall_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_overall_freq) &&
+ freq_included(channels, wpa_s->best_overall_freq)) {
params->freq = wpa_s->best_overall_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_24_freq) &&
+ freq_included(channels, wpa_s->best_24_freq)) {
params->freq = wpa_s->best_24_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_5_freq) &&
+ freq_included(channels, wpa_s->best_5_freq)) {
params->freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
+ } else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p,
+ channels))) {
+ params->freq = pref_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
+ "channels", params->freq);
} else {
- params->freq = 2412;
+ int chan;
+ for (chan = 0; chan < 11; chan++) {
+ params->freq = 2412 + chan * 5;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global,
+ params->freq) &&
+ freq_included(channels, params->freq))
+ break;
+ }
+ if (chan == 11) {
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
+ "allowed");
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
"known)", params->freq);
}
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq && !freq) {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
- "already using");
- params->freq = wpa_s->assoc_freq;
- }
-
- res = wpa_drv_shared_freq(wpa_s);
- if (res > 0 && !freq) {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
- "already using on a shared interface");
- params->freq = res;
- } else if (res > 0 && freq != res &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
- "while connected on another channel (%u MHz)",
- freq, res);
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ if (res < 0) {
+ os_free(freqs);
return -1;
}
+ num = res;
+ for (i = 0; i < num; i++) {
+ if (freq && freqs[i] == freq)
+ break;
+ if (!freq && freq_included(channels, freqs[i])) {
+ wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+ freqs[i]);
+ params->freq = freqs[i];
+ break;
+ }
+ }
+
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (freq)
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+ else
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
+ os_free(freqs);
+ return -1;
+ } else if (num == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+ }
+ }
+
+ os_free(freqs);
return 0;
}
@@ -3175,18 +5047,30 @@ 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))
+ if (!wpas_p2p_create_iface(wpa_s)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
+ "operations");
+ wpa_s->p2p_first_connection_timeout = 0;
return wpa_s;
+ }
if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
- WPA_IF_P2P_CLIENT) < 0)
+ WPA_IF_P2P_CLIENT) < 0) {
+ wpa_msg_global(wpa_s, MSG_ERROR,
+ "P2P: Failed to add group interface");
return NULL;
+ }
group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
if (group_wpa_s == NULL) {
+ wpa_msg_global(wpa_s, MSG_ERROR,
+ "P2P: Failed to initialize group interface");
wpas_p2p_remove_pending_group_interface(wpa_s);
return NULL;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
+ group_wpa_s->ifname);
+ group_wpa_s->p2p_first_connection_timeout = 0;
return group_wpa_s;
}
@@ -3196,74 +5080,36 @@ 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
+ * @ht40: Start GO with 40 MHz channel width
+ * @vht: Start GO 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 freq, int ht40, int vht)
{
struct p2p_go_neg_results params;
- unsigned int r;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ os_free(wpa_s->global->add_psk);
+ wpa_s->global->add_psk = NULL;
+
/* Make sure we are not running find during connection establishment */
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
- wpas_p2p_stop_find(wpa_s);
-
- if (freq == 2) {
- wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
- "band");
- if (wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
- freq = wpa_s->best_24_freq;
- wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
- "channel: %d MHz", freq);
- } else {
- os_get_random((u8 *) &r, sizeof(r));
- freq = 2412 + (r % 3) * 25;
- wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
- "channel: %d MHz", freq);
- }
- }
-
- if (freq == 5) {
- wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
- "band");
- if (wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq)) {
- freq = wpa_s->best_5_freq;
- wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
- "channel: %d MHz", freq);
- } else {
- os_get_random((u8 *) &r, sizeof(r));
- freq = 5180 + (r % 4) * 20;
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: Could not select "
- "5 GHz channel for P2P group");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
- "channel: %d MHz", freq);
- }
- }
+ wpas_p2p_stop_find_oper(wpa_s);
- if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
- "(%u MHz) is not supported for P2P uses",
- freq);
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
return -1;
- }
- if (wpas_p2p_init_go_params(wpa_s, &params, freq))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
return -1;
if (params.freq &&
- !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+ !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
"(%u MHz) is not supported for P2P uses",
params.freq);
@@ -3289,6 +5135,7 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
if (wpa_s == NULL)
return -1;
+ wpa_s->p2p_last_4way_hs_fail = NULL;
wpa_supplicant_ap_deinit(wpa_s);
@@ -3317,17 +5164,19 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
if (params->passphrase)
ssid->passphrase = os_strdup(params->passphrase);
- wpa_supplicant_select_network(wpa_s, ssid);
-
wpa_s->show_group_started = 1;
+ wpa_supplicant_select_network(wpa_s, ssid);
+
return 0;
}
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq)
+ int freq, int ht40, int vht,
+ const struct p2p_channels *channels,
+ int connection_timeout)
{
struct p2p_go_neg_results params;
int go = 0;
@@ -3342,8 +5191,13 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
return 0;
}
+ os_free(wpa_s->global->add_psk);
+ wpa_s->global->add_psk = NULL;
+
/* Make sure we are not running find during connection establishment */
- wpas_p2p_stop_find(wpa_s);
+ wpas_p2p_stop_find_oper(wpa_s);
+
+ wpa_s->p2p_fallback_to_go_neg = 0;
if (ssid->mode == WPAS_MODE_INFRA)
return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
@@ -3351,18 +5205,26 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, &params, freq))
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
return -1;
- params.role_go = 1;
- if (ssid->passphrase == NULL ||
- os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
- wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
- "group");
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
return -1;
+
+ params.role_go = 1;
+ params.psk_set = ssid->psk_set;
+ if (params.psk_set)
+ os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
+ if (ssid->passphrase) {
+ if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
+ wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in "
+ "persistent group");
+ return -1;
+ }
+ os_strlcpy(params.passphrase, ssid->passphrase,
+ sizeof(params.passphrase));
}
- os_strlcpy(params.passphrase, ssid->passphrase,
- sizeof(params.passphrase));
os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
params.ssid_len = ssid->ssid_len;
params.persistent_group = 1;
@@ -3371,6 +5233,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (wpa_s == NULL)
return -1;
+ wpa_s->p2p_first_connection_timeout = connection_timeout;
wpas_start_wps_go(wpa_s, &params, 0);
return 0;
@@ -3408,22 +5271,24 @@ static void wpas_p2p_idle_update(void *ctx, int idle)
if (!wpa_s->ap_iface)
return;
wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
- if (idle)
+ if (idle) {
+ if (wpa_s->global->p2p_fail_on_wps_complete &&
+ wpa_s->p2p_in_provisioning) {
+ wpas_p2p_grpform_fail_after_wps(wpa_s);
+ return;
+ }
wpas_p2p_set_group_idle_timeout(wpa_s);
- else
+ } else
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
}
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
- int persistent_group,
- int group_formation)
+ struct wpa_ssid *ssid)
{
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return NULL;
@@ -3431,9 +5296,9 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
if (cfg == NULL)
return NULL;
- if (persistent_group && wpa_s->conf->persistent_reconnect)
+ if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect)
cfg->persistent_group = 2;
- else if (persistent_group)
+ else if (ssid->p2p_persistent_group)
cfg->persistent_group = 1;
os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
if (wpa_s->max_stations &&
@@ -3441,6 +5306,9 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
cfg->max_clients = wpa_s->max_stations;
else
cfg->max_clients = wpa_s->conf->max_num_sta;
+ os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
+ cfg->ssid_len = ssid->ssid_len;
+ cfg->freq = ssid->frequency;
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
@@ -3448,7 +5316,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
group = p2p_group_init(wpa_s->global->p2p, cfg);
if (group == NULL)
os_free(cfg);
- if (!group_formation)
+ if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
p2p_group_notif_formation_done(group);
wpa_s->p2p_group = group;
return group;
@@ -3477,10 +5345,39 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
NULL);
+ wpa_s->p2p_go_group_formation_completed = 1;
+ if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+ /*
+ * Use a separate timeout for initial data connection to
+ * complete to allow the group to be removed automatically if
+ * something goes wrong in this step before the P2P group idle
+ * timeout mechanism is taken into use.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Re-start group formation timeout (%d seconds) as client for initial connection",
+ P2P_MAX_INITIAL_CONN_WAIT);
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ } else if (ssid) {
+ /*
+ * Use a separate timeout for initial data connection to
+ * complete to allow the group to be removed automatically if
+ * the client does not complete data connection successfully.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Re-start group formation timeout (%d seconds) as GO for initial connection",
+ 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);
+ /*
+ * Complete group formation on first successful data connection
+ */
+ wpa_s->p2p_go_group_formation_completed = 0;
+ }
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
- else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- wpa_drv_wps_success_cb(wpa_s, peer_addr);
wpas_group_formation_completed(wpa_s, 1);
}
@@ -3501,14 +5398,42 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
}
wpas_notify_p2p_wps_failed(wpa_s, fail);
+
+ if (wpa_s == wpa_s->global->p2p_group_formation) {
+ /*
+ * Allow some time for the failed WPS negotiation exchange to
+ * complete, but remove the group since group formation cannot
+ * succeed after provisioning failure.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout");
+ wpa_s->global->p2p_fail_on_wps_complete = 1;
+ eloop_deplete_timeout(0, 50000,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+}
+
+
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->p2p_fail_on_wps_complete ||
+ !wpa_s->p2p_in_provisioning)
+ return 0;
+
+ wpas_p2p_grpform_fail_after_wps(wpa_s);
+
+ return 1;
}
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method, int join)
+ const char *config_method,
+ enum wpas_p2p_prov_disc_use use)
{
u16 config_methods;
+ wpa_s->p2p_fallback_to_go_neg = 0;
+ wpa_s->pending_pd_use = NORMAL_PD;
if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
else if (os_strncmp(config_method, "keypad", 6) == 0)
@@ -3521,16 +5446,29 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
- config_methods, join);
+ if (use == WPAS_P2P_PD_AUTO) {
+ os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
+ wpa_s->pending_pd_config_methods = config_methods;
+ wpa_s->p2p_auto_pd = 1;
+ wpa_s->p2p_auto_join = 0;
+ wpa_s->pending_pd_before_join = 0;
+ wpa_s->auto_pd_scan_retry = 0;
+ wpas_p2p_stop_find(wpa_s);
+ wpa_s->p2p_join_scan_count = 0;
+ os_get_reltime(&wpa_s->p2p_auto_started);
+ wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
+ wpa_s->p2p_auto_started.sec,
+ wpa_s->p2p_auto_started.usec);
+ wpas_p2p_join_scan(wpa_s, NULL);
+ return 0;
}
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return -1;
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
- config_methods, join, 0);
+ config_methods, use == WPAS_P2P_PD_FOR_JOIN,
+ 0, 1);
}
@@ -3543,53 +5481,53 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
- if (!wpa_s->pending_action_tx)
+ if (!offchannel_pending_action_tx(wpa_s))
return;
wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
"operation request");
- wpabuf_free(wpa_s->pending_action_tx);
- wpa_s->pending_action_tx = NULL;
+ offchannel_clear_pending_action_tx(wpa_s);
}
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id)
+ const u8 *dev_id, unsigned int search_delay)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_find(wpa_s, timeout, type);
-
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+ wpa_s->p2p_in_provisioning)
return -1;
wpa_supplicant_cancel_sched_scan(wpa_s);
return p2p_find(wpa_s->global->p2p, timeout, type,
- num_req_dev_types, req_dev_types, dev_id);
+ num_req_dev_types, req_dev_types, dev_id,
+ search_delay);
}
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->p2p_cb_on_scan_complete = 0;
-
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_stop_find(wpa_s);
- return;
- }
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
+ return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+ if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+ return;
wpas_p2p_remove_pending_group_interface(wpa_s);
}
@@ -3666,15 +5604,27 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
const u8 *dst, const u8 *bssid,
- const u8 *ie, size_t ie_len)
+ const u8 *ie, size_t ie_len, int ssi_signal)
{
if (wpa_s->global->p2p_disabled)
return 0;
if (wpa_s->global->p2p == NULL)
return 0;
- return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len);
+ switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
+ ie, ie_len)) {
+ case P2P_PREQ_NOT_P2P:
+ wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
+ ssi_signal);
+ /* fall through */
+ case P2P_PREQ_MALFORMED:
+ case P2P_PREQ_NOT_LISTEN:
+ case P2P_PREQ_NOT_PROCESSED:
+ default: /* make gcc happy */
+ return 0;
+ case P2P_PREQ_PROCESSED:
+ return 1;
+ }
}
@@ -3719,9 +5669,6 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
{
wpa_s->p2p_long_listen = 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_reject(wpa_s, addr);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -3731,11 +5678,23 @@ 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)
+ struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+ int ht40, int vht, int pref_freq)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
+ int force_freq = 0;
+ int res;
+ int no_pref_freq_given = pref_freq == 0;
+ wpa_s->global->p2p_invite_group = NULL;
+ if (peer_addr)
+ os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+ else
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+
+ wpa_s->p2p_persistent_go_freq = freq;
+ wpa_s->p2p_go_ht40 = !!ht40;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -3760,16 +5719,26 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
}
wpa_s->pending_invite_ssid_id = ssid->id;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len,
- go_dev_addr, 1);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ role == P2P_INVITE_ROLE_GO);
+ if (res)
+ return res;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+ no_pref_freq_given && pref_freq > 0 &&
+ wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz for invitation due to p2p_ignore_shared_freq=1 configuration",
+ pref_freq);
+ pref_freq = 0;
+ }
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1);
+ ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
+ 1, pref_freq, -1);
}
@@ -3782,6 +5751,12 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
u8 *bssid = NULL;
struct wpa_ssid *ssid;
int persistent;
+ int freq = 0, force_freq = 0, pref_freq = 0;
+ int res;
+
+ wpa_s->p2p_persistent_go_freq = 0;
+ wpa_s->p2p_go_ht40 = 0;
+ wpa_s->p2p_go_vht = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -3799,6 +5774,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
return -1;
}
+ wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
ssid->ssid, ssid->ssid_len);
@@ -3808,6 +5784,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
bssid = wpa_s->own_addr;
if (go_dev_addr == NULL)
go_dev_addr = wpa_s->global->p2p_dev_addr;
+ freq = ssid->frequency;
} else {
role = P2P_INVITE_ROLE_CLIENT;
if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -3819,20 +5796,23 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
if (go_dev_addr == NULL &&
!is_zero_ether_addr(wpa_s->go_dev_addr))
go_dev_addr = wpa_s->go_dev_addr;
+ freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+ (int) wpa_s->assoc_freq;
}
wpa_s->parent->pending_invite_ssid_id = -1;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len,
- go_dev_addr, persistent);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ role == P2P_INVITE_ROLE_ACTIVE_GO);
+ if (res)
+ return res;
+ wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
- go_dev_addr, persistent);
+ ssid->ssid, ssid->ssid_len, force_freq,
+ go_dev_addr, persistent, pref_freq, -1);
}
@@ -3844,6 +5824,13 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
int network_id = -1;
int persistent;
int freq;
+ u8 ip[3 * 4];
+ char ip_addr[100];
+
+ if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
if (!wpa_s->show_group_started || !ssid)
return;
@@ -3863,23 +5850,33 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
(int) wpa_s->assoc_freq;
+
+ ip_addr[0] = '\0';
+ if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) {
+ os_snprintf(ip_addr, sizeof(ip_addr), " ip_addr=%u.%u.%u.%u "
+ "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
+ ip[0], ip[1], ip[2], ip[3],
+ ip[4], ip[5], ip[6], ip[7],
+ ip[8], ip[9], ip[10], ip[11]);
+ }
+
if (ssid->passphrase == NULL && ssid->psk_set) {
char psk[65];
wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
- MACSTR "%s",
- wpa_s->ifname, ssid_txt, freq, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+ wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s client ssid=\"%s\" freq=%d psk=%s "
+ "go_dev_addr=" MACSTR "%s%s",
+ wpa_s->ifname, ssid_txt, freq, psk,
+ MAC2STR(go_dev_addr),
+ persistent ? " [PERSISTENT]" : "", ip_addr);
} else {
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt, freq,
- ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+ wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s client ssid=\"%s\" freq=%d "
+ "passphrase=\"%s\" go_dev_addr=" MACSTR "%s%s",
+ wpa_s->ifname, ssid_txt, freq,
+ ssid->passphrase ? ssid->passphrase : "",
+ MAC2STR(go_dev_addr),
+ persistent ? " [PERSISTENT]" : "", ip_addr);
}
if (persistent)
@@ -3894,8 +5891,8 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
u32 interval1, u32 duration2, u32 interval2)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -3904,18 +5901,19 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
return -1;
- return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->assoc_freq,
- duration1, interval1, duration2, interval2);
+ ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->assoc_freq,
+ duration1, interval1, duration2, interval2);
+ if (ret == 0)
+ wpa_s->waiting_presence_resp = 1;
+
+ return ret;
}
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
unsigned int interval)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -3925,8 +5923,15 @@ int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
{
- return wpa_s->current_ssid != NULL &&
- wpa_s->current_ssid->p2p_group &&
+ if (wpa_s->current_ssid == NULL) {
+ /*
+ * current_ssid can be cleared when P2P client interface gets
+ * disconnected, so assume this interface was used as P2P
+ * client.
+ */
+ return 1;
+ }
+ return wpa_s->current_ssid->p2p_group &&
wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
}
@@ -3943,16 +5948,17 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
"group");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT);
}
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
{
- unsigned int timeout;
+ int timeout;
+
+ if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
return;
@@ -3964,6 +5970,13 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
if (timeout == 0)
return;
+ if (timeout < 0) {
+ if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA)
+ timeout = 0; /* special client mode no-timeout */
+ else
+ return;
+ }
+
if (wpa_s->p2p_in_provisioning) {
/*
* Use the normal group formation timeout during the
@@ -3975,6 +5988,19 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
return;
}
+ if (wpa_s->show_group_started) {
+ /*
+ * Use the normal group formation timeout between the end of
+ * the provisioning phase and completion of 4-way handshake to
+ * avoid terminating this process too early due to group idle
+ * timeout.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+ "while waiting for initial 4-way handshake to "
+ "complete");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
timeout);
eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
@@ -3982,27 +6008,44 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
}
-void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len)
+/* Returns 1 if the interface was removed */
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
- return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
+ return 0;
+
+ if (!locally_generated)
+ p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+ ie_len);
+
+ if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated &&
+ wpa_s->current_ssid &&
+ wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
+ wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
+ "session is ending");
+ if (wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION)
+ > 0)
+ return 1;
+ }
- p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+ return 0;
}
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len)
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
- p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+ if (!locally_generated)
+ p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+ ie_len);
}
@@ -4125,6 +6168,11 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
"update failed");
}
+
+ if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: No GO channel list "
+ "update failed");
+ }
}
}
@@ -4143,8 +6191,6 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
wpa_s->global->cross_connection = enabled;
p2p_set_cross_connect(wpa_s->global->p2p, enabled);
@@ -4159,9 +6205,10 @@ 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(iface->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
- iface->ifname, iface->cross_connect_uplink);
+ wpa_msg_global(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ iface->ifname,
+ iface->cross_connect_uplink);
}
}
@@ -4188,9 +6235,9 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
continue;
iface->cross_connect_in_use = 1;
- wpa_msg(iface->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
- iface->ifname, iface->cross_connect_uplink);
+ wpa_msg_global(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
}
}
@@ -4208,9 +6255,9 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
if (!iface->cross_connect_in_use)
continue;
- wpa_msg(iface->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
- iface->ifname, iface->cross_connect_uplink);
+ wpa_msg_global(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
iface->cross_connect_in_use = 0;
}
}
@@ -4224,8 +6271,9 @@ void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
wpas_p2p_disable_cross_connect(wpa_s);
else
wpas_p2p_enable_cross_connect(wpa_s);
- if (!wpa_s->ap_iface)
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+ if (!wpa_s->ap_iface &&
+ eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
}
@@ -4269,9 +6317,9 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
break;
wpa_s->cross_connect_in_use = 1;
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
- wpa_s->ifname, wpa_s->cross_connect_uplink);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
break;
}
}
@@ -4287,33 +6335,34 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
"session overlap");
if (wpa_s != wpa_s->parent)
wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
-
- if (wpa_s->global->p2p)
- p2p_group_formation_failed(wpa_s->global->p2p);
-
- eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
-
- wpas_group_formation_completed(wpa_s, 0);
+ wpas_p2p_group_formation_failed(wpa_s);
return 1;
}
void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
{
- struct p2p_channels chan;
+ struct p2p_channels chan, cli_chan;
if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
return;
os_memset(&chan, 0, sizeof(chan));
- if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+ os_memset(&cli_chan, 0, sizeof(cli_chan));
+ if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
"channel list");
return;
}
- p2p_update_channel_list(wpa_s->global->p2p, &chan);
+ p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
+}
+
+
+static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
}
@@ -4340,6 +6389,18 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
found = 1;
}
+ if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join");
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore;
+ found = 1;
+ }
+
+ if (wpa_s->pending_pd_before_join) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join");
+ wpa_s->pending_pd_before_join = 0;
+ found = 1;
+ }
+
wpas_p2p_stop_find(wpa_s);
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
@@ -4353,7 +6414,12 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
- wpas_p2p_group_delete(wpa_s);
+ if (wpa_s->p2p_in_provisioning) {
+ wpas_group_formation_completed(wpa_s, 0);
+ break;
+ }
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_REQUESTED);
break;
}
}
@@ -4374,8 +6440,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
"being available anymore");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE);
}
@@ -4383,7 +6448,7 @@ void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
int freq_24, int freq_5, int freq_overall)
{
struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+ if (p2p == NULL)
return;
p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
}
@@ -4394,7 +6459,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr)
u8 peer[ETH_ALEN];
struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+ if (p2p == NULL)
return -1;
if (hwaddr_aton(addr, peer))
@@ -4421,19 +6486,49 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
if (wpa_s == NULL)
return -1;
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
- wpas_p2p_group_delete(wpa_s);
-
- return 0;
+ return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED) < 0 ?
+ -1 : 0;
}
int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
{
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
- return p2p_in_progress(wpa_s->global->p2p);
+ ret = p2p_in_progress(wpa_s->global->p2p);
+ if (ret == 0) {
+ /*
+ * Check whether there is an ongoing WPS provisioning step (or
+ * other parts of group formation) on another interface since
+ * p2p_in_progress() does not report this to avoid issues for
+ * scans during such provisioning step.
+ */
+ if (wpa_s->global->p2p_group_formation &&
+ wpa_s->global->p2p_group_formation != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) "
+ "in group formation",
+ wpa_s->global->p2p_group_formation->ifname);
+ ret = 1;
+ }
+ }
+
+ if (!ret && wpa_s->global->p2p_go_wait_client.sec) {
+ struct os_reltime now;
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client,
+ P2P_MAX_INITIAL_CONN_WAIT_GO)) {
+ /* Wait for the first client has expired */
+ wpa_s->global->p2p_go_wait_client.sec = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Waiting for initial client connection during group formation");
+ ret = 1;
+ }
+ }
+
+ return ret;
}
@@ -4473,6 +6568,11 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
(ssid_len != s->ssid_len ||
os_memcmp(ssid, s->ssid, ssid_len) != 0))
continue;
+ if (addr == NULL) {
+ if (s->mode == WPAS_MODE_P2P_GO)
+ return s;
+ continue;
+ }
if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
return s; /* peer is GO in the persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
@@ -4492,7 +6592,986 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
+ if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL) > 0) {
+ /*
+ * This can happen if WPS provisioning step is not terminated
+ * cleanly (e.g., P2P Client does not send WSC_Done). Since the
+ * peer was able to connect, there is no need to time out group
+ * formation after this, though. In addition, this is used with
+ * the initial connection wait on the GO as a separate formation
+ * timeout and as such, expected to be hit after the initial WPS
+ * provisioning step.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+ }
+ if (!wpa_s->p2p_go_group_formation_completed) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first 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->global->p2p_go_wait_client.sec = 0;
if (addr == NULL)
return;
wpas_p2p_add_persistent_group_client(wpa_s, addr);
}
+
+
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added)
+{
+ struct wpa_supplicant *group = wpa_s;
+ if (wpa_s->global->p2p_group_formation)
+ group = wpa_s->global->p2p_group_formation;
+ wpa_s = wpa_s->parent;
+ offchannel_send_action_done(wpa_s);
+ if (group_added)
+ wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
+ wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
+ wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
+ 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_persistent_id,
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht);
+}
+
+
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->p2p_fallback_to_go_neg ||
+ wpa_s->p2p_in_provisioning <= 5)
+ return 0;
+
+ if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0)
+ return 0; /* peer operating as a GO */
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
+ "fallback to GO Negotiation");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+
+ return 1;
+}
+
+
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *ifs;
+
+ if (wpa_s->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
+ "concurrent operation",
+ P2P_CONCURRENT_SEARCH_DELAY);
+ return P2P_CONCURRENT_SEARCH_DELAY;
+ }
+
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s && ifs->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
+ "delay due to concurrent operation on "
+ "interface %s",
+ P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
+ return P2P_CONCURRENT_SEARCH_DELAY;
+ }
+ }
+
+ return 0;
+}
+
+
+static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *s, const u8 *addr,
+ int iface_addr)
+{
+ struct psk_list_entry *psk, *tmp;
+ int changed = 0;
+
+ dl_list_for_each_safe(psk, tmp, &s->psk_list, struct psk_list_entry,
+ list) {
+ if ((iface_addr && !psk->p2p &&
+ os_memcmp(addr, psk->addr, ETH_ALEN) == 0) ||
+ (!iface_addr && psk->p2p &&
+ os_memcmp(addr, psk->addr, ETH_ALEN) == 0)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove persistent group PSK list entry for "
+ MACSTR " p2p=%u",
+ MAC2STR(psk->addr), psk->p2p);
+ dl_list_del(&psk->list);
+ os_free(psk);
+ changed++;
+ }
+ }
+
+ return changed;
+}
+
+
+void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
+ const u8 *p2p_dev_addr,
+ const u8 *psk, size_t psk_len)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_ssid *persistent;
+ struct psk_list_entry *p;
+
+ if (psk_len != sizeof(p->psk))
+ return;
+
+ if (p2p_dev_addr) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR
+ " p2p_dev_addr=" MACSTR,
+ MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
+ if (is_zero_ether_addr(p2p_dev_addr))
+ p2p_dev_addr = NULL;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR,
+ MAC2STR(mac_addr));
+ }
+
+ if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: new_psk_cb during group formation");
+ /* To be added to persistent group once created */
+ if (wpa_s->global->add_psk == NULL) {
+ wpa_s->global->add_psk = os_zalloc(sizeof(*p));
+ if (wpa_s->global->add_psk == NULL)
+ return;
+ }
+ p = wpa_s->global->add_psk;
+ if (p2p_dev_addr) {
+ p->p2p = 1;
+ os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN);
+ } else {
+ p->p2p = 0;
+ os_memcpy(p->addr, mac_addr, ETH_ALEN);
+ }
+ os_memcpy(p->psk, psk, psk_len);
+ return;
+ }
+
+ if (ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Ignore new_psk_cb on not-persistent GO");
+ return;
+ }
+
+ persistent = wpas_p2p_get_persistent(wpa_s->parent, 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");
+ return;
+ }
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return;
+ if (p2p_dev_addr) {
+ p->p2p = 1;
+ os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN);
+ } else {
+ p->p2p = 0;
+ os_memcpy(p->addr, mac_addr, ETH_ALEN);
+ }
+ os_memcpy(p->psk, psk, psk_len);
+
+ if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS) {
+ struct psk_list_entry *last;
+ last = dl_list_last(&persistent->psk_list,
+ struct psk_list_entry, list);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove oldest PSK entry for "
+ MACSTR " (p2p=%u) to make room for a new one",
+ MAC2STR(last->addr), last->p2p);
+ dl_list_del(&last->list);
+ os_free(last);
+ }
+
+ wpas_p2p_remove_psk_entry(wpa_s->parent, persistent,
+ p2p_dev_addr ? p2p_dev_addr : mac_addr,
+ p2p_dev_addr == NULL);
+ if (p2p_dev_addr) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add new PSK for p2p_dev_addr="
+ MACSTR, MAC2STR(p2p_dev_addr));
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add new PSK for addr=" MACSTR,
+ MAC2STR(mac_addr));
+ }
+ dl_list_add(&persistent->psk_list, &p->list);
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->parent->conf->update_config &&
+ wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
+static void wpas_p2p_remove_psk(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *s, const u8 *addr,
+ int iface_addr)
+{
+ int res;
+
+ res = wpas_p2p_remove_psk_entry(wpa_s, s, addr, iface_addr);
+ if (res > 0) {
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ }
+}
+
+
+static void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s,
+ const u8 *peer, int iface_addr)
+{
+ struct hostapd_data *hapd;
+ struct hostapd_wpa_psk *psk, *prev, *rem;
+ struct sta_info *sta;
+
+ if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL ||
+ wpa_s->current_ssid->mode != WPAS_MODE_P2P_GO)
+ return;
+
+ /* Remove per-station PSK entry */
+ hapd = wpa_s->ap_iface->bss[0];
+ prev = NULL;
+ psk = hapd->conf->ssid.wpa_psk;
+ while (psk) {
+ if ((iface_addr && os_memcmp(peer, psk->addr, ETH_ALEN) == 0) ||
+ (!iface_addr &&
+ os_memcmp(peer, psk->p2p_dev_addr, ETH_ALEN) == 0)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove operating group PSK entry for "
+ MACSTR " iface_addr=%d",
+ MAC2STR(peer), iface_addr);
+ if (prev)
+ prev->next = psk->next;
+ else
+ hapd->conf->ssid.wpa_psk = psk->next;
+ rem = psk;
+ psk = psk->next;
+ os_free(rem);
+ } else {
+ prev = psk;
+ psk = psk->next;
+ }
+ }
+
+ /* Disconnect from group */
+ if (iface_addr)
+ sta = ap_get_sta(hapd, peer);
+ else
+ sta = ap_get_sta_p2p(hapd, peer);
+ if (sta) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disconnect peer " MACSTR
+ " (iface_addr=%d) from group",
+ MAC2STR(peer), iface_addr);
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_DEAUTH_LEAVING);
+ ap_sta_deauthenticate(hapd, sta, WLAN_REASON_DEAUTH_LEAVING);
+ }
+}
+
+
+void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
+ int iface_addr)
+{
+ struct wpa_ssid *s;
+ struct wpa_supplicant *w;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove client " MACSTR, MAC2STR(peer));
+
+ /* Remove from any persistent group */
+ for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+ if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
+ continue;
+ if (!iface_addr)
+ wpas_remove_persistent_peer(wpa_s, s, peer, 0);
+ wpas_p2p_remove_psk(wpa_s->parent, s, peer, iface_addr);
+ }
+
+ /* Remove from any operating group */
+ for (w = wpa_s->global->ifaces; w; w = w->next)
+ wpas_p2p_remove_client_go(w, peer, iface_addr);
+}
+
+
+static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_PSK_FAILURE);
+}
+
+
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+}
+
+
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_supplicant *iface;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (!iface->current_ssid ||
+ iface->current_ssid->frequency == freq ||
+ (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+ !iface->current_ssid->p2p_group))
+ continue;
+
+ /* Remove the connection with least priority */
+ if (!wpas_is_p2p_prioritized(iface)) {
+ /* STA connection has priority over existing
+ * P2P connection, so remove the interface. */
+ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict");
+ eloop_register_timeout(0, 0,
+ wpas_p2p_group_freq_conflict,
+ iface, NULL);
+ /* If connection in progress is P2P connection, do not
+ * proceed for the connection. */
+ if (wpa_s == iface)
+ return -1;
+ else
+ return 0;
+ } else {
+ /* P2P connection has priority, disable the STA network
+ */
+ wpa_supplicant_disable_network(wpa_s->global->ifaces,
+ ssid);
+ wpa_msg(wpa_s->global->ifaces, MSG_INFO,
+ WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
+ os_memset(wpa_s->global->ifaces->pending_bssid, 0,
+ ETH_ALEN);
+ /* If P2P connection is in progress, continue
+ * connecting...*/
+ if (wpa_s == iface)
+ return 0;
+ else
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid == NULL || !ssid->p2p_group)
+ return 0;
+
+ if (wpa_s->p2p_last_4way_hs_fail &&
+ wpa_s->p2p_last_4way_hs_fail == ssid) {
+ u8 go_dev_addr[ETH_ALEN];
+ struct wpa_ssid *persistent;
+
+ if (wpas_p2p_persistent_group(wpa_s, go_dev_addr,
+ ssid->ssid,
+ ssid->ssid_len) <= 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not determine whether 4-way handshake failures were for a persistent group");
+ goto disconnect;
+ }
+
+ 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,
+ 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,
+ P2P_EVENT_PERSISTENT_PSK_FAIL "%d",
+ persistent->id);
+ disconnect:
+ wpa_s->p2p_last_4way_hs_fail = NULL;
+ /*
+ * Remove the group from a timeout to avoid issues with caller
+ * continuing to use the interface if this is on a P2P group
+ * interface.
+ */
+ eloop_register_timeout(0, 0, wpas_p2p_psk_failure_removal,
+ wpa_s, NULL);
+ return 1;
+ }
+
+ wpa_s->p2p_last_4way_hs_fail = ssid;
+ return 0;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * wpas_p2p_nfc_handover(int ndef, struct wpabuf *wsc,
+ struct wpabuf *p2p)
+{
+ struct wpabuf *ret;
+ size_t wsc_len;
+
+ if (p2p == NULL) {
+ wpabuf_free(wsc);
+ wpa_printf(MSG_DEBUG, "P2P: No p2p buffer for handover");
+ return NULL;
+ }
+
+ wsc_len = wsc ? wpabuf_len(wsc) : 0;
+ ret = wpabuf_alloc(2 + wsc_len + 2 + wpabuf_len(p2p));
+ if (ret == NULL) {
+ wpabuf_free(wsc);
+ wpabuf_free(p2p);
+ return NULL;
+ }
+
+ wpabuf_put_be16(ret, wsc_len);
+ if (wsc)
+ wpabuf_put_buf(ret, wsc);
+ wpabuf_put_be16(ret, wpabuf_len(p2p));
+ wpabuf_put_buf(ret, p2p);
+
+ wpabuf_free(wsc);
+ wpabuf_free(p2p);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "P2P: Generated NFC connection handover message", ret);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_p2p(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to NDEF encapsulate handover request");
+ return NULL;
+ }
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+static int wpas_p2p_cli_freq(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **ssid, u8 *go_dev_addr)
+{
+ struct wpa_supplicant *iface;
+
+ if (go_dev_addr)
+ os_memset(go_dev_addr, 0, ETH_ALEN);
+ if (ssid)
+ *ssid = NULL;
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (iface->wpa_state < WPA_ASSOCIATING ||
+ iface->current_ssid == NULL || iface->assoc_freq == 0 ||
+ !iface->current_ssid->p2p_group ||
+ iface->current_ssid->mode != WPAS_MODE_INFRA)
+ continue;
+ if (ssid)
+ *ssid = iface->current_ssid;
+ if (go_dev_addr)
+ os_memcpy(go_dev_addr, iface->go_dev_addr, ETH_ALEN);
+ return iface->assoc_freq;
+ }
+ return 0;
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct wpabuf *wsc, *p2p;
+ struct wpa_ssid *ssid;
+ u8 go_dev_addr[ETH_ALEN];
+ int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: P2P disabled - cannot build handover request");
+ return NULL;
+ }
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No DH key available for handover request");
+ return NULL;
+ }
+
+ if (cli_freq == 0) {
+ wsc = wps_build_nfc_handover_req_p2p(
+ wpa_s->parent->wps, wpa_s->conf->wps_nfc_dh_pubkey);
+ } else
+ wsc = NULL;
+ p2p = p2p_build_nfc_handover_req(wpa_s->global->p2p, cli_freq,
+ go_dev_addr, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+
+ return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int tag)
+{
+ struct wpabuf *wsc, *p2p;
+ struct wpa_ssid *ssid;
+ u8 go_dev_addr[ETH_ALEN];
+ int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return NULL;
+
+ if (!tag && wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+
+ if (cli_freq == 0) {
+ wsc = wps_build_nfc_handover_sel_p2p(
+ wpa_s->parent->wps,
+ tag ? wpa_s->conf->wps_nfc_dev_pw_id :
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ tag ? wpa_s->conf->wps_nfc_dev_pw : NULL);
+ } else
+ wsc = NULL;
+ p2p = p2p_build_nfc_handover_sel(wpa_s->global->p2p, cli_freq,
+ go_dev_addr, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+
+ return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC "
+ "connection handover (freq=%d)",
+ params->go_freq);
+
+ if (params->go_freq && params->go_ssid_len) {
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memset(wpa_s->pending_join_iface_addr, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_join_dev_addr, params->go_dev_addr,
+ ETH_ALEN);
+ return wpas_p2p_join_start(wpa_s, params->go_freq,
+ params->go_ssid,
+ params->go_ssid_len);
+ }
+
+ 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);
+}
+
+
+static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params, int tag)
+{
+ int res, persistent;
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "P2P: Authorize join-group based on NFC "
+ "connection handover");
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ssid = wpa_s->current_ssid;
+ if (ssid == NULL)
+ continue;
+ if (ssid->mode != WPAS_MODE_P2P_GO)
+ continue;
+ if (wpa_s->ap_iface == NULL)
+ continue;
+ break;
+ }
+ if (wpa_s == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not find GO interface");
+ return -1;
+ }
+
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->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);
+ if (res)
+ return res;
+
+ if (!tag) {
+ wpa_printf(MSG_DEBUG, "P2P: Negotiated handover - wait for peer to join without invitation");
+ return 0;
+ }
+
+ if (!params->peer ||
+ !(params->peer->dev_capab & P2P_DEV_CAPAB_INVITATION_PROCEDURE))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invite peer " MACSTR
+ " to join", MAC2STR(params->peer->p2p_device_addr));
+
+ wpa_s->global->p2p_invite_group = wpa_s;
+ persistent = ssid->p2p_persistent_group &&
+ wpas_p2p_get_persistent(wpa_s->parent,
+ params->peer->p2p_device_addr,
+ ssid->ssid, ssid->ssid_len);
+ wpa_s->parent->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);
+}
+
+
+static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params,
+ int forced_freq)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate GO Negotiation based on NFC "
+ "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);
+}
+
+
+static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params,
+ int forced_freq)
+{
+ int res;
+
+ wpa_printf(MSG_DEBUG, "P2P: Authorize GO Negotiation based on NFC "
+ "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);
+ if (res)
+ return res;
+
+ res = wpas_p2p_listen(wpa_s, 60);
+ if (res) {
+ p2p_unauthorize(wpa_s->global->p2p,
+ params->peer->p2p_device_addr);
+ }
+
+ return res;
+}
+
+
+static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data,
+ int sel, int tag, int forced_freq)
+{
+ const u8 *pos, *end;
+ u16 len, id;
+ struct p2p_nfc_params params;
+ int res;
+
+ os_memset(&params, 0, sizeof(params));
+ params.sel = sel;
+
+ wpa_hexdump_buf(MSG_DEBUG, "P2P: Received NFC tag payload", data);
+
+ pos = wpabuf_head(data);
+ end = pos + wpabuf_len(data);
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of WSC "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
+ "attributes");
+ return -1;
+ }
+ params.wsc_attr = pos;
+ params.wsc_len = len;
+ pos += len;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of P2P "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
+ "attributes");
+ return -1;
+ }
+ params.p2p_attr = pos;
+ params.p2p_len = len;
+ pos += len;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: WSC attributes",
+ params.wsc_attr, params.wsc_len);
+ wpa_hexdump(MSG_DEBUG, "P2P: P2P attributes",
+ params.p2p_attr, params.p2p_len);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "P2P: Ignored extra data after P2P attributes",
+ pos, end - pos);
+ }
+
+ res = p2p_process_nfc_connection_handover(wpa_s->global->p2p, &params);
+ if (res)
+ return res;
+
+ if (params.next_step == NO_ACTION)
+ return 0;
+
+ if (params.next_step == BOTH_GO) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_BOTH_GO "peer=" MACSTR,
+ MAC2STR(params.peer->p2p_device_addr));
+ return 0;
+ }
+
+ if (params.next_step == PEER_CLIENT) {
+ if (!is_zero_ether_addr(params.go_dev_addr)) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+ "peer=" MACSTR " freq=%d go_dev_addr=" MACSTR
+ " ssid=\"%s\"",
+ MAC2STR(params.peer->p2p_device_addr),
+ params.go_freq,
+ MAC2STR(params.go_dev_addr),
+ wpa_ssid_txt(params.go_ssid,
+ params.go_ssid_len));
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+ "peer=" MACSTR " freq=%d",
+ MAC2STR(params.peer->p2p_device_addr),
+ params.go_freq);
+ }
+ return 0;
+ }
+
+ if (wpas_p2p_cli_freq(wpa_s, NULL, NULL)) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_WHILE_CLIENT "peer="
+ MACSTR, MAC2STR(params.peer->p2p_device_addr));
+ return 0;
+ }
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
+
+ if (params.oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "P2P: No peer OOB Dev Pw "
+ "received");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_printf(MSG_DEBUG, "P2P: Peer OOB Dev Pw %u", id);
+ wpa_hexdump(MSG_DEBUG, "P2P: Peer OOB Public Key hash",
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ os_memcpy(wpa_s->p2p_peer_oob_pubkey_hash,
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_s->p2p_peer_oob_pk_hash_known = 1;
+
+ if (tag) {
+ if (id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid "
+ "peer OOB Device Password Id %u", id);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - use peer OOB "
+ "Device Password Id %u", id);
+ wpa_hexdump_key(MSG_DEBUG, "P2P: Peer OOB Device Password",
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ wpa_s->p2p_oob_dev_pw_id = id;
+ wpa_s->p2p_oob_dev_pw = wpabuf_alloc_copy(
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Using abbreviated WPS handshake "
+ "without Device Password");
+ wpa_s->p2p_oob_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ }
+
+ switch (params.next_step) {
+ case NO_ACTION:
+ case BOTH_GO:
+ case PEER_CLIENT:
+ /* already covered above */
+ return 0;
+ case JOIN_GROUP:
+ return wpas_p2p_nfc_join_group(wpa_s, &params);
+ case AUTH_JOIN:
+ return wpas_p2p_nfc_auth_join(wpa_s, &params, tag);
+ case INIT_GO_NEG:
+ return wpas_p2p_nfc_init_go_neg(wpa_s, &params, forced_freq);
+ case RESP_GO_NEG:
+ /* TODO: use own OOB Dev Pw */
+ return wpas_p2p_nfc_resp_go_neg(wpa_s, &params, forced_freq);
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ return wpas_p2p_nfc_connection_handover(wpa_s, data, 1, 1, forced_freq);
+}
+
+
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel, int forced_freq)
+{
+ struct wpabuf *tmp;
+ int ret;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "NFC: P2P connection handover reported");
+
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Req",
+ wpabuf_head(req), wpabuf_len(req));
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Sel",
+ wpabuf_head(sel), wpabuf_len(sel));
+ if (forced_freq)
+ wpa_printf(MSG_DEBUG, "NFC: Forced freq %d", forced_freq);
+ tmp = ndef_parse_p2p(init ? sel : req);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not parse NDEF");
+ return -1;
+ }
+
+ ret = wpas_p2p_nfc_connection_handover(wpa_s, tmp, init, 0,
+ forced_freq);
+ wpabuf_free(tmp);
+
+ return ret;
+}
+
+
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
+{
+ const u8 *if_addr;
+ int go_intent = wpa_s->conf->p2p_go_intent;
+ struct wpa_supplicant *iface;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG, "P2P: Disable use of own NFC Tag");
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+ {
+ if (!iface->ap_iface)
+ continue;
+ hostapd_wps_nfc_token_disable(iface->ap_iface->bss[0]);
+ }
+ p2p_set_authorized_oob_dev_pw_id(wpa_s->global->p2p, 0,
+ 0, NULL);
+ if (wpa_s->p2p_nfc_tag_enabled)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
+ wpa_s->p2p_nfc_tag_enabled = 0;
+ return 0;
+ }
+
+ if (wpa_s->global->p2p_disabled)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw_id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: NFC password token not configured "
+ "to allow static handover cases");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Enable use of own NFC Tag");
+
+ wpa_s->p2p_oob_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+ wpa_s->p2p_peer_oob_pk_hash_known = 0;
+
+ wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+
+ if (wpa_s->create_p2p_iface) {
+ enum wpa_driver_if_type iftype;
+ /* Prepare to add a new interface for the group */
+ iftype = WPA_IF_P2P_GROUP;
+ if (go_intent == 15)
+ iftype = WPA_IF_P2P_GO;
+ if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+ "interface for the group");
+ return -1;
+ }
+
+ if_addr = wpa_s->pending_interface_addr;
+ } else
+ if_addr = wpa_s->own_addr;
+
+ wpa_s->p2p_nfc_tag_enabled = enabled;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ struct hostapd_data *hapd;
+ if (iface->ap_iface == NULL)
+ continue;
+ hapd = iface->ap_iface->bss[0];
+ wpabuf_free(hapd->conf->wps_nfc_dh_pubkey);
+ hapd->conf->wps_nfc_dh_pubkey =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ wpabuf_free(hapd->conf->wps_nfc_dh_privkey);
+ hapd->conf->wps_nfc_dh_privkey =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ wpabuf_free(hapd->conf->wps_nfc_dev_pw);
+ hapd->conf->wps_nfc_dev_pw =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+ hapd->conf->wps_nfc_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+
+ if (hostapd_wps_nfc_token_enable(iface->ap_iface->bss[0]) < 0) {
+ wpa_dbg(iface, MSG_DEBUG,
+ "P2P: Failed to enable NFC Tag for GO");
+ }
+ }
+ p2p_set_authorized_oob_dev_pw_id(
+ wpa_s->global->p2p, wpa_s->conf->wps_nfc_dev_pw_id, go_intent,
+ if_addr);
+
+ return 0;
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 4887823..685313c 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -2,14 +2,8 @@
* wpa_supplicant - P2P
* Copyright (c) 2009-2010, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef P2P_SUPPLICANT_H
@@ -19,31 +13,44 @@ enum p2p_wps_method;
struct p2p_go_neg_results;
enum p2p_send_action_result;
struct p2p_peer_info;
+struct p2p_channels;
+struct wps_event_fail;
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
void wpas_p2p_deinit_global(struct wpa_global *global);
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s);
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
- int persistent_group, int join, int auth, int go_intent,
- int freq);
+ int persistent_group, int auto_join, int join,
+ int auth, int go_intent, int freq, int persistent_id,
+ int pd, int ht40, int vht);
void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration);
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
+ int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq);
+ int freq, int ht40, int vht);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq);
+ int freq, int ht40, int vht,
+ const struct p2p_channels *channels,
+ int connection_timeout);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
- int persistent_group,
- int group_formation);
+ struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int registrar);
+enum wpas_p2p_prov_disc_use {
+ WPAS_P2P_PD_FOR_GO_NEG,
+ WPAS_P2P_PD_FOR_JOIN,
+ WPAS_P2P_PD_AUTO
+};
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method, int join);
+ const char *config_method,
+ enum wpas_p2p_prov_disc_use use);
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
const u8 *data, size_t data_len,
enum p2p_send_action_result result);
@@ -53,39 +60,28 @@ enum p2p_discovery_type;
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id);
+ const u8 *dev_id, unsigned int search_delay);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
u8 *buf, size_t len, int p2p_group);
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
const u8 *dst, const u8 *bssid,
- const u8 *ie, size_t ie_len);
+ const u8 *ie, size_t ie_len,
+ int ssi_signal);
void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
const u8 *sa, const u8 *bssid,
u8 category, const u8 *data, size_t len, int freq);
void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
-void wpas_dev_found(void *ctx, const u8 *addr,
- const struct p2p_peer_info *info,
- int new_device);
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
-void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
- const u8 *dev_addr, const u8 *pri_dev_type,
- const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab, const u8 *group_id,
- size_t group_id_len);
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
- u16 update_indic, const u8 *tlvs, size_t tlvs_len);
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len);
-void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
- const struct wpabuf *tlvs);
-void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
- u8 version, const char *query);
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req);
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+ u8 version, const char *query);
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *role);
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
const u8 *dst, u8 dialog_token,
const struct wpabuf *resp_tlvs);
@@ -101,7 +97,8 @@ int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
const char *service);
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);
+ struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+ int ht40, int vht, 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);
void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -109,10 +106,12 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
u32 interval1, u32 duration2, u32 interval2);
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
unsigned int interval);
-void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len);
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated);
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len);
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated);
void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
int duration);
@@ -129,6 +128,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr);
int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
@@ -137,5 +137,40 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
size_t ssid_len);
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr);
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht80_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,
+ const u8 *psk, size_t psk_len);
+void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
+ int iface_addr);
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef);
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int tag);
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq);
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel, int forced_freq);
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
+
+#ifdef CONFIG_P2P
+int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
+void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_P2P */
+static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
+{
+}
+#endif /* CONFIG_P2P */
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index d38a6bb..ed57085 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -2,14 +2,8 @@
* WPA Supplicant - test code for pre-authentication
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
* Not used in production version.
@@ -33,9 +27,6 @@
#include "drivers/driver.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
struct wpa_driver_ops *wpa_drivers[] = { NULL };
@@ -44,12 +35,6 @@ struct preauth_test_data {
};
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
- wpa_supplicant_disassociate(wpa_s, reason_code);
-}
-
-
static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -244,7 +229,6 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
- ctx->disassociate = _wpa_supplicant_disassociate;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -322,7 +306,7 @@ int main(int argc, char *argv[])
}
os_memset(&wpa_s, 0, sizeof(wpa_s));
- wpa_s.conf = wpa_config_read(argv[1]);
+ wpa_s.conf = wpa_config_read(argv[1], NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", argv[1]);
return -1;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 01413a8..18d243e 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -17,12 +11,14 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
@@ -71,7 +67,8 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_P2P
- if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p) {
+ if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
+ !wpa_s->conf->p2p_disabled) {
wpa_s->wps->dev.p2p = 1;
if (!wps) {
wps = 1;
@@ -85,15 +82,33 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_WPS */
-int wpa_supplicant_enabled_networks(struct wpa_config *conf)
+/**
+ * wpa_supplicant_enabled_networks - Check whether there are enabled networks
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 if no networks are enabled, >0 if networks are enabled
+ *
+ * This function is used to figure out whether any networks (or Interworking
+ * with enabled credentials and auto_interworking) are present in the current
+ * configuration.
+ */
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
{
- struct wpa_ssid *ssid = conf->ssid;
- int count = 0;
+ struct wpa_ssid *ssid = wpa_s->conf->ssid;
+ int count = 0, disabled = 0;
while (ssid) {
- if (!ssid->disabled)
+ if (!wpas_network_disabled(wpa_s, ssid))
count++;
+ else
+ disabled++;
ssid = ssid->next;
}
+ if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+ wpa_s->conf->auto_interworking)
+ count++;
+ if (count == 0 && disabled > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled "
+ "networks)", disabled);
+ }
return count;
}
@@ -102,7 +117,7 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
while (ssid) {
- if (!ssid->disabled)
+ if (!wpas_network_disabled(wpa_s, ssid))
break;
ssid = ssid->next;
}
@@ -126,89 +141,67 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
}
-static int int_array_len(const int *a)
-{
- int i;
- for (i = 0; a && a[i]; i++)
- ;
- return i;
-}
-
-
-static void int_array_concat(int **res, const int *a)
+static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
{
- int reslen, alen, i;
- int *n;
-
- reslen = int_array_len(*res);
- alen = int_array_len(a);
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_driver_scan_params *params = work->ctx;
+ int ret;
- n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
- if (n == NULL) {
- os_free(*res);
- *res = NULL;
+ if (deinit) {
+ wpa_scan_free_params(params);
return;
}
- for (i = 0; i <= alen; i++)
- n[reslen + i] = a[i];
- *res = n;
-}
-
-
-static int freq_cmp(const void *a, const void *b)
-{
- int _a = *(int *) a;
- int _b = *(int *) b;
-
- if (_a == 0)
- return 1;
- if (_b == 0)
- return -1;
- return _a - _b;
-}
+ wpa_supplicant_notify_scanning(wpa_s, 1);
-static void int_array_sort_unique(int *a)
-{
- int alen;
- int i, j;
-
- if (a == NULL)
+ if (wpa_s->clear_driver_scan_cache)
+ params->only_new_results = 1;
+ ret = wpa_drv_scan(wpa_s, params);
+ wpa_scan_free_params(params);
+ work->ctx = NULL;
+ if (ret) {
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+ wpas_notify_scan_done(wpa_s, 0);
+ radio_work_done(work);
return;
-
- alen = int_array_len(a);
- qsort(a, alen, sizeof(int), freq_cmp);
-
- i = 0;
- j = 1;
- while (a[i] && a[j]) {
- if (a[i] == a[j]) {
- j++;
- continue;
- }
- a[++i] = a[j++];
}
- if (a[i])
- i++;
- a[i] = 0;
+
+ os_get_reltime(&wpa_s->scan_trigger_time);
+ wpa_s->scan_runs++;
+ wpa_s->normal_scans++;
+ wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
+ wpa_s->scan_work = work;
}
+/**
+ * wpa_supplicant_trigger_scan - Request driver to start a scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
- int ret;
+ struct wpa_driver_scan_params *ctx;
- wpa_supplicant_notify_scanning(wpa_s, 1);
+ if (wpa_s->scan_work) {
+ wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
+ return -1;
+ }
- ret = wpa_drv_scan(wpa_s, params);
- if (ret) {
- wpa_supplicant_notify_scanning(wpa_s, 0);
- wpas_notify_scan_done(wpa_s, 0);
- } else
- wpa_s->scan_runs++;
+ ctx = wpa_scan_clone_params(params);
+ if (ctx == NULL)
+ return -1;
- return ret;
+ if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+ {
+ wpa_scan_free_params(ctx);
+ return -1;
+ }
+
+ return 0;
}
@@ -236,10 +229,9 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-static int
-wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- int interval)
+int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ int interval)
{
int ret;
@@ -254,7 +246,7 @@ wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
{
int ret;
@@ -342,8 +334,19 @@ static void wpa_supplicant_optimize_freqs(
if (params->freqs)
params->freqs[0] = wpa_s->wps_freq;
wpa_s->after_wps--;
- }
+ } else if (wpa_s->after_wps)
+ wpa_s->after_wps--;
+ if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
+ {
+ /* Optimize provisioning scan based on already known channel */
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
+ wpa_s->wps_freq);
+ params->freqs = os_zalloc(2 * sizeof(int));
+ if (params->freqs)
+ params->freqs[0] = wpa_s->wps_freq;
+ wpa_s->known_wps_freq = 0; /* only do this once */
+ }
#endif /* CONFIG_WPS */
}
@@ -392,7 +395,9 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
if (wps) {
struct wpabuf *wps_ie;
- wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+ wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
+ DEV_PW_DEFAULT,
+ &wpa_s->wps->dev,
wpa_s->wps->uuid, req_type,
0, NULL);
if (wps_ie) {
@@ -412,32 +417,138 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_WPS */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
+ wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
return extra_ie;
}
+#ifdef CONFIG_P2P
+
+/*
+ * Check whether there are any enabled networks or credentials that could be
+ * used for a non-P2P connection.
+ */
+static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid))
+ continue;
+ if (!ssid->p2p_group)
+ return 1;
+ }
+
+ if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+ wpa_s->conf->auto_interworking)
+ return 1;
+
+ return 0;
+}
+
+#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)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band - use empty list */
+ params->freqs = os_zalloc(sizeof(int));
+ return;
+ }
+
+ params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ params->freqs[count++] = mode->channels[i].freq;
+ }
+}
+
+
+static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ if (wpa_s->hw.modes == NULL)
+ return; /* unknown what channels the driver supports */
+ if (params->freqs)
+ return; /* already using a limited channel set */
+ if (wpa_s->setband == WPA_SETBAND_5G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params);
+ else if (wpa_s->setband == WPA_SETBAND_2G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ params);
+}
+
+
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
- int scan_req = 0, ret;
- struct wpabuf *extra_ie;
+ int ret;
+ struct wpabuf *extra_ie = NULL;
struct wpa_driver_scan_params params;
+ struct wpa_driver_scan_params *scan_params;
size_t max_ssids;
enum wpa_states prev_state;
+ if (wpa_s->pno || wpa_s->pno_sched_pending) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
+ return;
+ }
+
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
return;
}
- if (wpa_s->disconnected && !wpa_s->scan_req) {
+ if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
return;
}
- if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
- !wpa_s->scan_req) {
+ if (wpa_s->scanning) {
+ /*
+ * If we are already in scanning state, we shall reschedule the
+ * the incoming scan request.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ return;
+ }
+
+ if (!wpa_supplicant_enabled_networks(wpa_s) &&
+ wpa_s->scan_req == NORMAL_SCAN_REQ) {
wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
return;
@@ -458,14 +569,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
#ifdef CONFIG_P2P
if (wpas_p2p_in_progress(wpa_s)) {
- if (wpa_s->wpa_state == WPA_SCANNING) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
- "while P2P operation is in progress");
- wpa_supplicant_req_scan(wpa_s, 5, 0);
- } else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while "
- "P2P operation is in progress");
- }
+ wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
+ wpa_supplicant_req_scan(wpa_s, 5, 0);
return;
}
#endif /* CONFIG_P2P */
@@ -478,8 +583,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
max_ssids = WPAS_MAX_SCAN_SSIDS;
}
- scan_req = wpa_s->scan_req;
- wpa_s->scan_req = 0;
+ wpa_s->last_scan_req = wpa_s->scan_req;
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
os_memset(&params, 0, sizeof(params));
@@ -488,7 +593,16 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
- if (scan_req != 2 && wpa_s->connect_without_scan) {
+ /*
+ * If autoscan has set its own scanning parameters
+ */
+ if (wpa_s->autoscan_params != NULL) {
+ scan_params = wpa_s->autoscan_params;
+ goto scan;
+ }
+
+ if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
+ wpa_s->connect_without_scan) {
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid == wpa_s->connect_without_scan)
break;
@@ -502,6 +616,19 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
}
+#ifdef CONFIG_P2P
+ if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
+ wpa_s->go_params) {
+ wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
+ wpa_s->p2p_in_provisioning,
+ wpa_s->show_group_started);
+ params.ssids[0].ssid = wpa_s->go_params->ssid;
+ params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
+ params.num_ssids = 1;
+ goto ssid_list_set;
+ }
+#endif /* CONFIG_P2P */
+
/* Find the starting point from which to continue scanning */
ssid = wpa_s->conf->ssid;
if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
@@ -514,8 +641,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
}
- if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+ if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
+ wpa_s->conf->ap_scan == 2) {
wpa_s->connect_without_scan = NULL;
+ wpa_s->prev_scan_wildcard = 0;
wpa_supplicant_assoc_try(wpa_s, ssid);
return;
} else if (wpa_s->conf->ap_scan == 2) {
@@ -530,7 +659,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
if (ssid == NULL && max_ssids > 1)
ssid = wpa_s->conf->ssid;
while (ssid) {
- if (!ssid->disabled && ssid->scan_ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->scan_ssid) {
wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
ssid->ssid, ssid->ssid_len);
params.ssids[params.num_ssids].ssid =
@@ -550,7 +680,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
- if (tssid->disabled)
+ if (wpas_network_disabled(wpa_s, tssid))
continue;
if ((params.freqs || !freqs_set) && tssid->scan_freq) {
int_array_concat(&params.freqs,
@@ -564,25 +694,59 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
int_array_sort_unique(params.freqs);
}
- if (ssid) {
- wpa_s->prev_scan_ssid = ssid;
- if (max_ssids > 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
- "the scan request");
- params.num_ssids++;
+ if (ssid && max_ssids == 1) {
+ /*
+ * If the driver is limited to 1 SSID at a time interleave
+ * wildcard SSID scans with specific SSID scans to avoid
+ * waiting a long time for a wildcard scan.
+ */
+ if (!wpa_s->prev_scan_wildcard) {
+ params.ssids[0].ssid = NULL;
+ params.ssids[0].ssid_len = 0;
+ wpa_s->prev_scan_wildcard = 1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
+ "wildcard SSID (Interleave with specific)");
+ } else {
+ wpa_s->prev_scan_ssid = ssid;
+ wpa_s->prev_scan_wildcard = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Starting AP scan for specific SSID: %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific "
- "SSID(s)");
+ } else if (ssid) {
+ /* max_ssids > 1 */
+
+ wpa_s->prev_scan_ssid = ssid;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
+ "the scan request");
+ params.num_ssids++;
+ } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_passive && params.num_ssids == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
} else {
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
params.num_ssids++;
wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
"SSID");
}
+#ifdef CONFIG_P2P
+ssid_list_set:
+#endif /* CONFIG_P2P */
wpa_supplicant_optimize_freqs(wpa_s, &params);
extra_ie = wpa_supplicant_extra_ies(wpa_s);
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_only_new)
+ params.only_new_results = 1;
+
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
+ wpa_s->manual_scan_freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
+ params.freqs = wpa_s->manual_scan_freqs;
+ wpa_s->manual_scan_freqs = NULL;
+ }
+
if (params.freqs == NULL && wpa_s->next_scan_freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
"generated frequency list");
@@ -590,6 +754,32 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
} else
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ wpa_setband_scan_freqs(wpa_s, &params);
+
+ /* See if user specified frequencies. If so, scan only those. */
+ if (wpa_s->conf->freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->freq_list");
+ int_array_concat(&params.freqs, wpa_s->conf->freq_list);
+ }
+
+ /* Use current associated channel? */
+ if (wpa_s->conf->scan_cur_freq && !params.freqs) {
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ params.freqs = os_calloc(num + 1, sizeof(int));
+ if (params.freqs) {
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ if (num > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
+ "current operating channels since "
+ "scan_cur_freq is enabled");
+ } else {
+ os_free(params.freqs);
+ params.freqs = NULL;
+ }
+ }
+ }
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, &params.num_filter_ssids);
@@ -599,7 +789,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#ifdef CONFIG_P2P
- if (wpa_s->p2p_in_provisioning) {
+ if (wpa_s->p2p_in_provisioning ||
+ (wpa_s->show_group_started && wpa_s->go_params)) {
/*
* The interface may not yet be in P2P mode, so we have to
* explicitly request P2P probe to disable CCK rates.
@@ -608,7 +799,48 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#endif /* CONFIG_P2P */
- ret = wpa_supplicant_trigger_scan(wpa_s, &params);
+ scan_params = &params;
+
+scan:
+#ifdef CONFIG_P2P
+ /*
+ * If the driver does not support multi-channel concurrency and a
+ * virtual interface that shares the same radio with the wpa_s interface
+ * is operating there may not be need to scan other channels apart from
+ * the current operating channel on the other virtual interface. Filter
+ * out other channels in case we are trying to find a connection for a
+ * station interface when we are not configured to prefer station
+ * connection and a concurrent operation is already in process.
+ */
+ if (wpa_s->scan_for_connection &&
+ wpa_s->last_scan_req == NORMAL_SCAN_REQ &&
+ !scan_params->freqs && !params.freqs &&
+ wpas_is_p2p_prioritized(wpa_s) &&
+ wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+ non_p2p_network_enabled(wpa_s)) {
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ params.freqs = os_calloc(num + 1, sizeof(int));
+ if (params.freqs) {
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ if (num > 0 && num == wpa_s->num_multichan_concurrent) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
+ } else {
+ os_free(params.freqs);
+ params.freqs = NULL;
+ }
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
+
+ if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
+ !wpa_s->manual_scan_freqs) {
+ /* Restore manual_scan_freqs for the next attempt */
+ wpa_s->manual_scan_freqs = params.freqs;
+ params.freqs = NULL;
+ }
wpabuf_free(extra_ie);
os_free(params.freqs);
@@ -618,11 +850,38 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
if (prev_state != wpa_s->wpa_state)
wpa_supplicant_set_state(wpa_s, prev_state);
+ /* Restore scan_req since we will try to scan again */
+ wpa_s->scan_req = wpa_s->last_scan_req;
wpa_supplicant_req_scan(wpa_s, 1, 0);
+ } else {
+ wpa_s->scan_for_connection = 0;
}
}
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
+{
+ struct os_reltime remaining, new_int;
+ int cancelled;
+
+ cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
+ &remaining);
+
+ new_int.sec = sec;
+ new_int.usec = 0;
+ if (cancelled && os_reltime_before(&remaining, &new_int)) {
+ new_int.sec = remaining.sec;
+ new_int.usec = remaining.usec;
+ }
+
+ if (cancelled) {
+ eloop_register_timeout(new_int.sec, new_int.usec,
+ wpa_supplicant_scan, wpa_s, NULL);
+ }
+ wpa_s->scan_interval = sec;
+}
+
+
/**
* wpa_supplicant_req_scan - Schedule a scan for neighboring access points
* @wpa_s: Pointer to wpa_supplicant data
@@ -634,32 +893,19 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
*/
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
- /* If there's at least one network that should be specifically scanned
- * then don't cancel the scan and reschedule. Some drivers do
- * background scanning which generates frequent scan results, and that
- * causes the specific SSID scan to get continually pushed back and
- * never happen, which causes hidden APs to never get probe-scanned.
- */
- if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
- wpa_s->conf->ap_scan == 1) {
- struct wpa_ssid *ssid = wpa_s->conf->ssid;
-
- while (ssid) {
- if (!ssid->disabled && ssid->scan_ssid)
- break;
- ssid = ssid->next;
- }
- if (ssid) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
- "ensure that specific SSID scans occur");
- return;
- }
+ int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
+ NULL);
+ if (res == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
+ sec, usec);
+ } else if (res == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner",
+ sec, usec);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec",
+ sec, usec);
+ eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
}
-
- wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
- sec, usec);
- eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
- eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
}
@@ -668,6 +914,7 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
* @wpa_s: Pointer to wpa_supplicant data
* @sec: Number of seconds after which to scan
* @usec: Number of microseconds after which to scan
+ * Returns: 0 on success or -1 otherwise
*
* This function is used to schedule periodic scans for neighboring
* access points after the specified time.
@@ -689,6 +936,7 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
/**
* wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
* @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 is sched_scan was started or -1 otherwise
*
* This function is used to schedule periodic scans for neighboring
* access points repeating the scan continuously.
@@ -696,11 +944,14 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_driver_scan_params params;
+ struct wpa_driver_scan_params *scan_params;
enum wpa_states prev_state;
struct wpa_ssid *ssid = NULL;
struct wpabuf *extra_ie = NULL;
int ret;
unsigned int max_sched_scan_ssids;
+ int wildcard = 0;
+ int need_ssids;
if (!wpa_s->sched_scan_supported)
return -1;
@@ -709,9 +960,56 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
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 || wpa_s->conf->disable_scan_offload)
+ return -1;
- if (wpa_s->sched_scanning)
+ if (wpa_s->sched_scanning) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
return 0;
+ }
+
+ need_ssids = 0;
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
+ /* Use wildcard SSID to find this network */
+ wildcard = 1;
+ } else if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->ssid_len)
+ need_ssids++;
+
+#ifdef CONFIG_WPS
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+ /*
+ * Normal scan is more reliable and faster for WPS
+ * operations and since these are for short periods of
+ * time, the benefit of trying to use sched_scan would
+ * be limited.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+ "sched_scan for WPS");
+ return -1;
+ }
+#endif /* CONFIG_WPS */
+ }
+ if (wildcard)
+ need_ssids++;
+
+ if (wpa_s->normal_scans < 3 &&
+ (need_ssids <= wpa_s->max_scan_ssids ||
+ wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
+ /*
+ * When normal scan can speed up operations, use that for the
+ * first operations before starting the sched_scan to allow
+ * user space sleep more. We do this only if the normal scan
+ * has functionality that is suitable for this or if the
+ * sched_scan does not have better support for multiple SSIDs.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+ "sched_scan for initial scans (normal_scans=%d)",
+ wpa_s->normal_scans);
+ return -1;
+ }
os_memset(&params, 0, sizeof(params));
@@ -724,6 +1022,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+ if (wpa_s->autoscan_params != NULL) {
+ scan_params = wpa_s->autoscan_params;
+ goto scan;
+ }
+
/* Find the starting point from which to continue scanning */
ssid = wpa_s->conf->ssid;
if (wpa_s->prev_sched_ssid) {
@@ -738,30 +1041,50 @@ 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");
-
- wpa_s->sched_scan_interval = 2;
+ 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;
wpa_s->prev_sched_ssid = ssid;
}
+ if (wildcard) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
+ params.num_ssids++;
+ }
+
while (ssid) {
- if (ssid->disabled) {
- wpa_s->prev_sched_ssid = ssid;
- ssid = ssid->next;
- continue;
- }
+ if (wpas_network_disabled(wpa_s, ssid))
+ goto next;
- if (params.filter_ssids && ssid->ssid && ssid->ssid_len) {
+ if (params.num_filter_ssids < wpa_s->max_match_sets &&
+ params.filter_ssids && ssid->ssid && ssid->ssid_len) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
ssid->ssid, ssid->ssid_len);
params.filter_ssids[params.num_filter_ssids].ssid_len =
ssid->ssid_len;
params.num_filter_ssids++;
+ } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
+ {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
+ "filter for sched_scan - drop filter");
+ os_free(params.filter_ssids);
+ params.filter_ssids = NULL;
+ params.num_filter_ssids = 0;
}
- if (ssid->scan_ssid) {
+ if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
+ if (params.num_ssids == max_sched_scan_ssids)
+ break; /* only room for broadcast SSID */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "add to active scan ssid: %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
params.ssids[params.num_ssids].ssid =
ssid->ssid;
params.ssids[params.num_ssids].ssid_len =
@@ -769,19 +1092,23 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
params.num_ssids++;
if (params.num_ssids >= max_sched_scan_ssids) {
wpa_s->prev_sched_ssid = ssid;
+ do {
+ ssid = ssid->next;
+ } while (ssid &&
+ (wpas_network_disabled(wpa_s, ssid) ||
+ !ssid->scan_ssid));
break;
}
}
- if (params.num_filter_ssids >= wpa_s->max_match_sets)
- break;
+ next:
wpa_s->prev_sched_ssid = ssid;
ssid = ssid->next;
}
- if (!params.num_ssids) {
+ if (params.num_filter_ssids == 0) {
os_free(params.filter_ssids);
- return 0;
+ params.filter_ssids = NULL;
}
extra_ie = wpa_supplicant_extra_ies(wpa_s);
@@ -790,11 +1117,25 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
params.extra_ies_len = wpabuf_len(extra_ie);
}
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Starting sched scan: interval %d timeout %d",
- wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+ if (wpa_s->conf->filter_rssi)
+ params.filter_rssi = wpa_s->conf->filter_rssi;
+
+ scan_params = &params;
+
+scan:
+ if (ssid || !wpa_s->first_sched_scan) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Starting sched scan: interval %d timeout %d",
+ wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Starting sched scan: interval %d (no timeout)",
+ wpa_s->sched_scan_interval);
+ }
+
+ wpa_setband_scan_freqs(wpa_s, scan_params);
- ret = wpa_supplicant_start_sched_scan(wpa_s, &params,
+ ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
@@ -814,8 +1155,16 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
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;
+ wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+ }
}
+ /* If there is no more ssids, start next time from the beginning */
+ if (!ssid)
+ wpa_s->prev_sched_ssid = NULL;
+
return 0;
}
@@ -835,6 +1184,23 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
/**
+ * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a delayed scheduled scan.
+ */
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->sched_scan_supported)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan");
+ eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout,
+ wpa_s, NULL);
+}
+
+
+/**
* wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
* @wpa_s: Pointer to wpa_supplicant data
*
@@ -851,6 +1217,16 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpa_supplicant_notify_scanning - Indicate possible scan state change
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @scanning: Whether scanning is currently in progress
+ *
+ * This function is to generate scanning notifycations. It is called whenever
+ * there may have been a change in scanning (scan started, completed, stopped).
+ * wpas_notify_scanning() is called whenever the scanning state changed from the
+ * previously notified state.
+ */
void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
int scanning)
{
@@ -883,6 +1259,15 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
}
+/**
+ * wpa_scan_get_ie - Fetch a specified information element from a scan result
+ * @res: Scan result entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
{
const u8 *end, *pos;
@@ -902,6 +1287,15 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
}
+/**
+ * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type)
{
@@ -923,52 +1317,65 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
}
-struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
- u32 vendor_type)
+/**
+ * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ *
+ * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+ u32 vendor_type)
{
- struct wpabuf *buf;
const u8 *end, *pos;
- buf = wpabuf_alloc(res->ie_len);
- if (buf == NULL)
+ if (res->beacon_ie_len == 0)
return NULL;
pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
+ pos += res->ie_len;
+ end = pos + res->beacon_ie_len;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+ return pos;
pos += 2 + pos[1];
}
- if (wpabuf_len(buf) == 0) {
- wpabuf_free(buf);
- buf = NULL;
- }
-
- return buf;
+ return NULL;
}
-struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
- const struct wpa_scan_res *res, u32 vendor_type)
+/**
+ * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the scan result. The caller is responsible
+ * for freeing the returned buffer.
+ */
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+ u32 vendor_type)
{
struct wpabuf *buf;
const u8 *end, *pos;
- if (res->beacon_ie_len == 0)
- return NULL;
- buf = wpabuf_alloc(res->beacon_ie_len);
+ buf = wpabuf_alloc(res->ie_len);
if (buf == NULL)
return NULL;
pos = (const u8 *) (res + 1);
- pos += res->ie_len;
- end = pos + res->beacon_ie_len;
+ end = pos + res->ie_len;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
@@ -1114,6 +1521,7 @@ static int wpa_scan_result_wps_compar(const void *a, const void *b)
static void dump_scan_res(struct wpa_scan_results *scan_res)
{
+#ifndef CONFIG_NO_STDOUT_DEBUG
size_t i;
if (scan_res->res == NULL || scan_res->num == 0)
@@ -1123,20 +1531,84 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *r = scan_res->res[i];
+ u8 *pos;
if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
== WPA_SCAN_LEVEL_DBM) {
int snr = r->level - r->noise;
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d snr=%d%s flags=0x%x",
+ "noise=%d level=%d snr=%d%s flags=0x%x "
+ "age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
r->noise, r->level, snr,
- snr >= GREAT_SNR ? "*" : "", r->flags);
+ snr >= GREAT_SNR ? "*" : "", r->flags,
+ r->age);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d flags=0x%x",
+ "noise=%d level=%d flags=0x%x age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, r->flags);
+ r->noise, r->level, r->flags, r->age);
}
+ pos = (u8 *) (r + 1);
+ if (r->ie_len)
+ wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
+ pos += r->ie_len;
+ if (r->beacon_ie_len)
+ wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
+ pos, r->beacon_ie_len);
+ }
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+/**
+ * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to check
+ * Returns: 0 if the BSSID is filtered or 1 if not
+ *
+ * This function is used to filter out specific BSSIDs from scan reslts mainly
+ * for testing purposes (SET bssid_filter ctrl_iface command).
+ */
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->bssid_filter == NULL)
+ return 1;
+
+ for (i = 0; i < wpa_s->bssid_filter_count; i++) {
+ if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
+ ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res)
+{
+ size_t i, j;
+
+ if (wpa_s->bssid_filter == NULL)
+ return;
+
+ for (i = 0, j = 0; i < res->num; i++) {
+ if (wpa_supplicant_filter_bssid_match(wpa_s,
+ res->res[i]->bssid)) {
+ res->res[j++] = res->res[i];
+ } else {
+ os_free(res->res[i]);
+ res->res[i] = NULL;
+ }
+ }
+
+ if (res->num != j) {
+ wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
+ (int) (res->num - j));
+ res->num = j;
}
}
@@ -1165,9 +1637,17 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
return NULL;
}
+ if (scan_res->fetch_time.sec == 0) {
+ /*
+ * Make sure we have a valid timestamp if the driver wrapper
+ * does not set this.
+ */
+ os_get_reltime(&scan_res->fetch_time);
+ }
+ filter_scan_res(wpa_s, scan_res);
#ifdef CONFIG_WPS
- if (wpas_wps_in_progress(wpa_s)) {
+ if (wpas_wps_searching(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
"provisioning rules");
compar = wpa_scan_result_wps_compar;
@@ -1180,13 +1660,26 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)
- wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
+ wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
+ &scan_res->fetch_time);
wpa_bss_update_end(wpa_s, info, new_scan);
return scan_res;
}
+/**
+ * wpa_supplicant_update_scan_results - Update scan results from the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function updates the BSS table within wpa_supplicant based on the
+ * currently available scan results from the driver without requesting a new
+ * scan. This is used in cases where the driver indicates an association
+ * (including roaming within ESS) and wpa_supplicant does not yet have the
+ * needed information to complete the connection (e.g., to perform validation
+ * steps in 4-way handshake).
+ */
int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
{
struct wpa_scan_results *scan_res;
@@ -1197,3 +1690,114 @@ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
return 0;
}
+
+
+/**
+ * scan_only_handler - Reports scan results
+ */
+void scan_only_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+ 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;
+ } else {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ }
+ wpas_notify_scan_results(wpa_s);
+ wpas_notify_scan_done(wpa_s, 1);
+ if (wpa_s->scan_work) {
+ struct wpa_radio_work *work = wpa_s->scan_work;
+ wpa_s->scan_work = NULL;
+ radio_work_done(work);
+ }
+}
+
+
+int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
+{
+ return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
+}
+
+
+struct wpa_driver_scan_params *
+wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
+{
+ struct wpa_driver_scan_params *params;
+ size_t i;
+ u8 *n;
+
+ params = os_zalloc(sizeof(*params));
+ if (params == NULL)
+ return NULL;
+
+ for (i = 0; i < src->num_ssids; i++) {
+ if (src->ssids[i].ssid) {
+ n = os_malloc(src->ssids[i].ssid_len);
+ if (n == NULL)
+ goto failed;
+ os_memcpy(n, src->ssids[i].ssid,
+ src->ssids[i].ssid_len);
+ params->ssids[i].ssid = n;
+ params->ssids[i].ssid_len = src->ssids[i].ssid_len;
+ }
+ }
+ params->num_ssids = src->num_ssids;
+
+ if (src->extra_ies) {
+ n = os_malloc(src->extra_ies_len);
+ if (n == NULL)
+ goto failed;
+ os_memcpy(n, src->extra_ies, src->extra_ies_len);
+ params->extra_ies = n;
+ params->extra_ies_len = src->extra_ies_len;
+ }
+
+ if (src->freqs) {
+ int len = int_array_len(src->freqs);
+ params->freqs = os_malloc((len + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ goto failed;
+ os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int));
+ }
+
+ if (src->filter_ssids) {
+ params->filter_ssids = os_malloc(sizeof(*params->filter_ssids) *
+ src->num_filter_ssids);
+ if (params->filter_ssids == NULL)
+ goto failed;
+ os_memcpy(params->filter_ssids, src->filter_ssids,
+ sizeof(*params->filter_ssids) *
+ src->num_filter_ssids);
+ params->num_filter_ssids = src->num_filter_ssids;
+ }
+
+ params->filter_rssi = src->filter_rssi;
+ params->p2p_probe = src->p2p_probe;
+ params->only_new_results = src->only_new_results;
+
+ return params;
+
+failed:
+ wpa_scan_free_params(params);
+ return NULL;
+}
+
+
+void wpa_scan_free_params(struct wpa_driver_scan_params *params)
+{
+ size_t i;
+
+ if (params == NULL)
+ return;
+
+ for (i = 0; i < params->num_ssids; i++)
+ os_free((u8 *) params->ssids[i].ssid);
+ os_free((u8 *) params->extra_ies);
+ os_free(params->freqs);
+ os_free(params->filter_ssids);
+ os_free(params);
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 7fb84e6..e4c8989 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -1,26 +1,21 @@
/*
* WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef SCAN_H
#define SCAN_H
-int wpa_supplicant_enabled_networks(struct wpa_config *conf);
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
int sec, int usec);
int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
int scanning);
@@ -34,9 +29,22 @@ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type);
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+ u32 vendor_type);
struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
u32 vendor_type);
-struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
- const struct wpa_scan_res *res, u32 vendor_type);
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
+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);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 78a91eb..451f5ae 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1,15 +1,9 @@
/*
* wpa_supplicant - SME
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -20,6 +14,7 @@
#include "common/ieee802_11_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
+#include "common/sae.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "config.h"
@@ -29,23 +24,122 @@
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
#include "notify.h"
-#include "blacklist.h"
#include "bss.h"
#include "scan.h"
#include "sme.h"
+#include "hs20_supplicant.h"
#define SME_AUTH_TIMEOUT 5
#define SME_ASSOC_TIMEOUT 5
static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_IEEE80211W */
-void sme_authenticate(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, struct wpa_ssid *ssid)
+#ifdef CONFIG_SAE
+
+static int index_within_array(const int *array, int idx)
+{
+ int i;
+ for (i = 0; i < idx; i++) {
+ if (array[i] <= 0)
+ return 0;
+ }
+ return 1;
+}
+
+
+static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ /* Configuration may have changed, so validate current index */
+ if (!index_within_array(groups, wpa_s->sme.sae_group_index))
+ return -1;
+
+ for (;;) {
+ int group = groups[wpa_s->sme.sae_group_index];
+ if (group < 0)
+ break;
+ if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+ wpa_s->sme.sae.group);
+ return 0;
+ }
+ wpa_s->sme.sae_group_index++;
+ }
+
+ return -1;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *bssid)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ if (ssid->passphrase == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (sme_set_sae_group(wpa_s) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
+ return NULL;
+ }
+
+ if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase),
+ &wpa_s->sme.sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
+
+ len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, 1); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
+
+ return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, 2); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ sae_write_confirm(&wpa_s->sme.sae, buf);
+
+ return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+static void sme_send_authentication(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ int start)
{
struct wpa_driver_auth_params params;
struct wpa_ssid *old_ssid;
@@ -56,10 +150,14 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
const u8 *md = NULL;
#endif /* CONFIG_IEEE80211R */
int i, bssid_changed;
+ struct wpabuf *resp = NULL;
+ u8 ext_capab[10];
+ int ext_capab_len;
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
"the network");
+ wpas_connect_work_done(wpa_s);
return;
}
@@ -100,6 +198,21 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
"0x%x", params.auth_alg);
}
+#ifdef CONFIG_SAE
+ if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
+ const u8 *rsn;
+ struct wpa_ie_data ied;
+
+ rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (rsn &&
+ wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
+ if (wpa_key_mgmt_sae(ied.key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+ params.auth_alg = WPA_AUTH_ALG_SAE;
+ }
+ }
+ }
+#endif /* CONFIG_SAE */
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i])
@@ -116,13 +229,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
- (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))) {
+ wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
- try_opportunistic = ssid->proactive_key_caching &&
+ try_opportunistic = (ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc :
+ ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid,
@@ -134,13 +245,19 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
&wpa_s->sme.assoc_req_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites");
+ wpas_connect_work_done(wpa_s);
return;
}
- } else if (ssid->key_mgmt &
- (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+ /*
+ * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+ * use non-WPA since the scan results did not indicate that the
+ * AP is using WPA or WPA2.
+ */
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_s->sme.assoc_req_ie_len = 0;
+ } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_s->sme.assoc_req_ie,
@@ -148,6 +265,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites (no "
"scan results)");
+ wpas_connect_work_done(wpa_s);
return;
}
#ifdef CONFIG_WPS
@@ -179,8 +297,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
}
- if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X)) {
+ if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) {
if (wpa_s->sme.assoc_req_ie_len + 5 <
sizeof(wpa_s->sme.assoc_req_ie)) {
struct rsn_mdie *mdie;
@@ -208,8 +325,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
- wpa_s->sme.mfp = ssid->ieee80211w;
- if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w;
+ if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data _ie;
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
@@ -237,23 +355,49 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking) {
+#ifdef CONFIG_HS20
+ if (is_hs20_network(wpa_s, ssid, bss)) {
+ struct wpabuf *hs20;
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ wpas_hs20_add_indication(hs20);
+ 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 */
+
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
u8 *pos = wpa_s->sme.assoc_req_ie;
if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
pos += 2 + pos[1];
- os_memmove(pos + 6, pos,
+ os_memmove(pos + ext_capab_len, pos,
wpa_s->sme.assoc_req_ie_len -
(pos - wpa_s->sme.assoc_req_ie));
- wpa_s->sme.assoc_req_ie_len += 6;
- *pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x80; /* Bit 31 - Interworking */
+ wpa_s->sme.assoc_req_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
+ }
+
+#ifdef CONFIG_SAE
+ if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+ if (start)
+ resp = sme_auth_build_sae_commit(wpa_s, ssid,
+ bss->bssid);
+ else
+ resp = sme_auth_build_sae_confirm(wpa_s);
+ if (resp == NULL) {
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+ params.sae_data = wpabuf_head(resp);
+ params.sae_data_len = wpabuf_len(resp);
+ wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
}
-#endif /* CONFIG_INTERWORKING */
+#endif /* CONFIG_SAE */
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
@@ -277,6 +421,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
"driver failed");
wpas_connection_failed(wpa_s, bss->bssid);
wpa_supplicant_mark_disassoc(wpa_s);
+ wpabuf_free(resp);
+ wpas_connect_work_done(wpa_s);
return;
}
@@ -287,9 +433,144 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
* Association will be started based on the authentication event from
* the driver.
*/
+
+ wpabuf_free(resp);
}
+static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_connect_work *cwork = work->ctx;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+
+ if (deinit) {
+ wpas_connect_work_free(cwork);
+ return;
+ }
+
+ wpa_s->connect_work = work;
+
+ if (!wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
+ sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
+}
+
+
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+ struct wpa_connect_work *cwork;
+
+ if (bss == NULL || ssid == NULL)
+ return;
+ if (wpa_s->connect_work) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist");
+ return;
+ }
+
+ cwork = os_zalloc(sizeof(*cwork));
+ if (cwork == NULL)
+ return;
+ cwork->bss = bss;
+ cwork->ssid = ssid;
+ cwork->sme = 1;
+
+#ifdef CONFIG_SAE
+ wpa_s->sme.sae.state = SAE_NOTHING;
+ wpa_s->sme.sae.send_confirm = 0;
+ wpa_s->sme.sae_group_index = 0;
+#endif /* CONFIG_SAE */
+
+ if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1,
+ sme_auth_start_cb, cwork) < 0)
+ wpas_connect_work_free(cwork);
+}
+
+
+#ifdef CONFIG_SAE
+
+static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
+ u16 status_code, const u8 *data, size_t len)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
+ "status code %u", auth_transaction, status_code);
+
+ if (auth_transaction == 1 &&
+ status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
+ wpa_s->sme.sae.state == SAE_COMMITTED &&
+ wpa_s->current_bss && wpa_s->current_ssid) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE anti-clogging token "
+ "requested");
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = wpabuf_alloc_copy(data, len);
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 1);
+ return 0;
+ }
+
+ if (auth_transaction == 1 &&
+ status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ wpa_s->sme.sae.state == SAE_COMMITTED &&
+ wpa_s->current_bss && wpa_s->current_ssid) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ wpa_s->sme.sae_group_index++;
+ if (sme_set_sae_group(wpa_s) < 0)
+ return -1; /* no other groups enabled */
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 1);
+ return 0;
+ }
+
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
+
+ if (auth_transaction == 1) {
+ int *groups = wpa_s->conf->sae_groups;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
+ if (wpa_s->current_bss == NULL ||
+ wpa_s->current_ssid == NULL)
+ return -1;
+ if (wpa_s->sme.sae.state != SAE_COMMITTED)
+ return -1;
+ if (groups && groups[0] <= 0)
+ groups = NULL;
+ if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
+ groups) != WLAN_STATUS_SUCCESS)
+ return -1;
+
+ if (sae_process_commit(&wpa_s->sme.sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
+ "commit");
+ return -1;
+ }
+
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = NULL;
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 0);
+ return 0;
+ } else if (auth_transaction == 2) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
+ if (wpa_s->sme.sae.state != SAE_CONFIRMED)
+ return -1;
+ if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0)
+ return -1;
+ wpa_s->sme.sae.state = SAE_ACCEPTED;
+ sae_clear_temp_data(&wpa_s->sme.sae);
+ return 1;
+ }
+
+ return -1;
+}
+#endif /* CONFIG_SAE */
+
+
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -314,14 +595,34 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
}
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
- " auth_type=%d status_code=%d",
+ " auth_type=%d auth_transaction=%d status_code=%d",
MAC2STR(data->auth.peer), data->auth.auth_type,
- data->auth.status_code);
+ data->auth.auth_transaction, data->auth.status_code);
wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
data->auth.ies, data->auth.ies_len);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+#ifdef CONFIG_SAE
+ if (data->auth.auth_type == WLAN_AUTH_SAE) {
+ int res;
+ res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
+ data->auth.status_code, data->auth.ies,
+ data->auth.ies_len);
+ if (res < 0) {
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+ }
+ if (res != 1)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
+ "4-way handshake");
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN);
+ }
+#endif /* CONFIG_SAE */
+
if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
"code %d)", data->auth.status_code);
@@ -335,6 +636,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
return;
}
+ wpas_connect_work_done(wpa_s);
+
switch (data->auth.auth_type) {
case WLAN_AUTH_OPEN:
wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
@@ -378,17 +681,41 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
{
struct wpa_driver_associate_params params;
struct ieee802_11_elems elems;
+#ifdef CONFIG_HT_OVERRIDES
+ struct ieee80211_ht_capabilities htcaps;
+ struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ struct ieee80211_vht_capabilities vhtcaps;
+ struct ieee80211_vht_capabilities vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
os_memset(&params, 0, sizeof(params));
params.bssid = bssid;
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
params.freq = wpa_s->sme.freq;
+ params.bg_scan_period = wpa_s->current_ssid ?
+ wpa_s->current_ssid->bg_scan_period : -1;
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
- params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
- params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+ params.pairwise_suite = wpa_s->pairwise_cipher;
+ params.group_suite = wpa_s->group_cipher;
+#ifdef CONFIG_HT_OVERRIDES
+ os_memset(&htcaps, 0, sizeof(htcaps));
+ os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+ params.htcaps = (u8 *) &htcaps;
+ params.htcaps_mask = (u8 *) &htcaps_mask;
+ wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ os_memset(&vhtcaps, 0, sizeof(vhtcaps));
+ os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
+ params.vhtcaps = &vhtcaps;
+ params.vhtcaps_mask = &vhtcaps_mask;
+ wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
params.wpa_ie = wpa_s->sme.ft_ies;
@@ -530,7 +857,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
void sme_event_disassoc(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+ struct disassoc_info *info)
{
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
if (wpa_s->sme.prev_bssid_set) {
@@ -608,9 +935,259 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_IEEE80211W
sme_stop_sa_query(wpa_s);
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = NULL;
+ sae_clear_data(&wpa_s->sme.sae);
+#endif /* CONFIG_SAE */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+ eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+ const u8 *chan_list, u8 num_channels,
+ u8 num_intol)
+{
+ struct ieee80211_2040_bss_coex_ie *bc_ie;
+ struct ieee80211_2040_intol_chan_report *ic_report;
+ struct wpabuf *buf;
+
+ wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
+ MAC2STR(wpa_s->bssid));
+
+ buf = wpabuf_alloc(2 + /* action.category + action_code */
+ sizeof(struct ieee80211_2040_bss_coex_ie) +
+ sizeof(struct ieee80211_2040_intol_chan_report) +
+ num_channels);
+ if (buf == NULL)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
+
+ bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
+ bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
+ bc_ie->length = 1;
+ if (num_intol)
+ bc_ie->coex_param |= WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
+
+ if (num_channels > 0) {
+ ic_report = wpabuf_put(buf, sizeof(*ic_report));
+ ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
+ ic_report->length = num_channels + 1;
+ ic_report->op_class = 0;
+ os_memcpy(wpabuf_put(buf, num_channels), chan_list,
+ num_channels);
+ }
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Failed to send 20/40 BSS Coexistence frame");
+ }
+
+ wpabuf_free(buf);
+}
+
+
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+ const u8 *ie;
+ u16 ht_cap;
+ u8 chan_list[P2P_MAX_CHANNELS], channel;
+ u8 num_channels = 0, num_intol = 0, i;
+
+ if (!wpa_s->sme.sched_obss_scan)
+ return 0;
+
+ wpa_s->sme.sched_obss_scan = 0;
+ if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+ return 1;
+
+ /*
+ * Check whether AP uses regulatory triplet or channel triplet in
+ * country info. Right now the operating class of the BSS channel
+ * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
+ * based on the assumption that operating class triplet is not used in
+ * beacon frame. If the First Channel Number/Operating Extension
+ * Identifier octet has a positive integer value of 201 or greater,
+ * then its operating class triplet.
+ *
+ * TODO: If Supported Operating Classes element is present in beacon
+ * frame, have to lookup operating class in Annex E and fill them in
+ * 2040 coex frame.
+ */
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+ if (ie && (ie[1] >= 6) && (ie[5] >= 201))
+ return 1;
+
+ os_memset(chan_list, 0, sizeof(chan_list));
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ /* Skip other band bss */
+ enum hostapd_hw_mode mode;
+ mode = ieee80211_freq_to_chan(bss->freq, &channel);
+ if (mode != HOSTAPD_MODE_IEEE80211G &&
+ mode != HOSTAPD_MODE_IEEE80211B)
+ continue;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+ ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+ if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+ /* Check whether the channel is already considered */
+ for (i = 0; i < num_channels; i++) {
+ if (channel == chan_list[i])
+ break;
+ }
+ if (i != num_channels)
+ continue;
+
+ if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+ num_intol++;
+
+ chan_list[num_channels++] = channel;
+ }
+ }
+
+ sme_send_2040_bss_coex(wpa_s, chan_list, num_channels, num_intol);
+ return 1;
+}
+
+
+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)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band - use empty list */
+ params->freqs = os_zalloc(sizeof(int));
+ return;
+ }
+
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ params->freqs[count++] = mode->channels[i].freq;
+ }
+}
+
+
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_driver_scan_params params;
+
+ if (!wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG, "SME OBSS: Ignore scan request");
+ return;
+ }
+
+ os_memset(&params, 0, sizeof(params));
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params);
+ wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
+
+ if (wpa_supplicant_trigger_scan(wpa_s, &params))
+ wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
+ else
+ wpa_s->sme.sched_obss_scan = 1;
+ os_free(params.freqs);
+
+ eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+ sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
+{
+ const u8 *ie;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_hw_modes *hw_mode = NULL;
+ int i;
+
+ eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+ wpa_s->sme.sched_obss_scan = 0;
+ if (!enable)
+ return;
+
+ /*
+ * Schedule OBSS scan if driver is using station SME in wpa_supplicant
+ * or it expects OBSS scan to be performed by wpa_supplicant.
+ */
+ if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
+ ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA)
+ return;
+
+ if (!wpa_s->hw.modes)
+ return;
+
+ /* only HT caps in 11g mode are relevant */
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ hw_mode = &wpa_s->hw.modes[i];
+ if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ break;
+ }
+
+ /* Driver does not support HT40 for 11g or doesn't have 11g. */
+ if (i == wpa_s->hw.num_modes || !hw_mode ||
+ !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return;
+
+ if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
+ return; /* Not associated on 2.4 GHz band */
+
+ /* Check whether AP supports HT40 */
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_CAP);
+ if (!ie || ie[1] < 2 ||
+ !(WPA_GET_LE16(ie + 2) & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return; /* AP does not support HT40 */
+
+ ie = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS);
+ if (!ie || ie[1] < 14)
+ return; /* AP does not request OBSS scans */
+
+ wpa_s->sme.obss_scan_int = WPA_GET_LE16(ie + 6);
+ if (wpa_s->sme.obss_scan_int < 10) {
+ wpa_printf(MSG_DEBUG, "SME: Invalid OBSS Scan Interval %u "
+ "replaced with the minimum 10 sec",
+ wpa_s->sme.obss_scan_int);
+ wpa_s->sme.obss_scan_int = 10;
+ }
+ wpa_printf(MSG_DEBUG, "SME: OBSS Scan Interval %u sec",
+ wpa_s->sme.obss_scan_int);
+ eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+ sme_obss_scan_timeout, wpa_s, NULL);
}
@@ -622,9 +1199,9 @@ static const unsigned int sa_query_retry_timeout = 201;
static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
{
u32 tu;
- struct os_time now, passed;
- os_get_time(&now);
- os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed);
+ struct os_reltime now, passed;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->sme.sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (sa_query_max_timeout < tu) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
@@ -667,14 +1244,14 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
sme_check_sa_query_timeout(wpa_s))
return;
- nbuf = os_realloc(wpa_s->sme.sa_query_trans_id,
- (wpa_s->sme.sa_query_count + 1) *
- WLAN_SA_QUERY_TR_ID_LEN);
+ nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
+ wpa_s->sme.sa_query_count + 1,
+ WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (wpa_s->sme.sa_query_count == 0) {
/* Starting a new SA Query procedure */
- os_get_time(&wpa_s->sme.sa_query_start);
+ os_get_reltime(&wpa_s->sme.sa_query_start);
}
trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
wpa_s->sme.sa_query_trans_id = nbuf;
@@ -700,7 +1277,7 @@ static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
}
-void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
os_free(wpa_s->sme.sa_query_trans_id);
@@ -714,12 +1291,12 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
{
struct wpa_ssid *ssid;
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
- return;
if (wpa_s->wpa_state != WPA_COMPLETED)
return;
ssid = wpa_s->current_ssid;
- if (ssid == NULL || ssid->ieee80211w == 0)
+ if (ssid == NULL ||
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
return;
if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
return;
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index a59b38d..04404c1 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -2,14 +2,8 @@
* wpa_supplicant - SME
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef SME_H
@@ -31,7 +25,7 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
union wpa_event_data *data);
void sme_event_disassoc(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data);
+ struct disassoc_info *info);
void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *da, u16 reason_code);
void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
@@ -41,6 +35,9 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
const u8 *prev_pending_bssid);
void sme_deinit(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+
#else /* CONFIG_SME */
static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
@@ -77,7 +74,7 @@ static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
}
static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+ struct disassoc_info *info)
{
}
@@ -101,6 +98,16 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s)
{
}
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
+ int enable)
+{
+}
+
#endif /* CONFIG_SME */
#endif /* SME_H */
diff --git a/wpa_supplicant/symbian/README.symbian b/wpa_supplicant/symbian/README.symbian
deleted file mode 100644
index 9d3b811..0000000
--- a/wpa_supplicant/symbian/README.symbian
+++ /dev/null
@@ -1,24 +0,0 @@
-wpa_supplicant for Symbian
-==========================
-
-Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> and
-contributors
-All Rights Reserved.
-
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-
-This directory includes project files for testing experimental Symbian
-(e.g., Nokia S60 3rd Ed) builds. The Symbian port is not really
-complete or expected to work, but these files can be used to verify
-that the build itself can be completed successfully.
-
-These files have been successfully tested with Nokia S60 3rd Edition
-MR SDK.
-
-Build files can be created and a phone release build can be run with
-following commands:
-
-bldmake bldfiles
-abld build gcce urel
diff --git a/wpa_supplicant/symbian/bld.inf b/wpa_supplicant/symbian/bld.inf
deleted file mode 100644
index a1fc582..0000000
--- a/wpa_supplicant/symbian/bld.inf
+++ /dev/null
@@ -1,8 +0,0 @@
-PRJ_PLATFORMS
-WINSCW GCCE
-
-PRJ_EXPORTS
-
-PRJ_MMPFILES
-
-wpa_supplicant.mmp
diff --git a/wpa_supplicant/symbian/wpa_supplicant.mmp b/wpa_supplicant/symbian/wpa_supplicant.mmp
deleted file mode 100644
index e018e05..0000000
--- a/wpa_supplicant/symbian/wpa_supplicant.mmp
+++ /dev/null
@@ -1,38 +0,0 @@
-TARGET wpa_supplicant.exe
-UID 0x0 0x0
-VENDORID 0
-TARGETTYPE exe
-
-SYSTEMINCLUDE \epoc32\include \epoc32\include\variant \epoc32\include\ecom \epoc32\include\libc
-
-USERINCLUDE .. ..\..\src ..\..\src\utils
-
-SOURCEPATH ..
-SOURCE main_symbian.cpp
-SOURCE config.c config_file.c
-SOURCE eapol_sm.c
-SOURCE wpa_supplicant.c events.c
-SOURCEPATH ..\..\src\rsn_supp
-SOURCE wpa.c preauth.c pmksa_cache.c peerkey.c wpa_ie.c
-SOURCEPATH ..\..\src\drivers
-SOURCE drivers.c driver_common.c
-SOURCEPATH ..\..\src\common
-SOURCE wpa_common.c
-SOURCEPATH ..\..\src\utils
-SOURCE os_none.c common.c wpa_debug.c eloop_none.c base64.c
-SOURCEPATH ..\..\src\crypto
-SOURCE sha1.c md5.c rc4.c des.c aes-cbc.c aes-ctr.c aes-eax.c aes-encblock.c aes-omac1.c aes-unwrap.c aes-wrap.c aes.c ms_funcs.c
-SOURCE tls_internal.c crypto_internal.c
-SOURCEPATH ..\..\src\tls
-SOURCE asn1.c bignum.c rsa.c x509v3.c tlsv1_client.c tlsv1_common.c
-SOURCEPATH ..\..\src\l2_packet
-SOURCE l2_packet_none.c
-SOURCEPATH ..\..\src\eap_peer
-SOURCE eap.c eap_methods.c
-SOURCE eap_md5.c eap_tls.c eap_mschapv2.c eap_peap.c eap_gtc.c
-SOURCE eap_ttls.c eap_otp.c eap_leap.c eap_tls_common.c eap_tlv.c
-SOURCE eap_fast.c eap_fast_pac.c
-SOURCEPATH ..\..\src\eap_common
-SOURCE eap_common.c
-
-LIBRARY euser.lib estlib.lib
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 76aba12..bfdee25 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -10,4 +10,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired@.service.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
index ff384ae..20ba0ad 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-wired@.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -10,4 +10,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-wired@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant@.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index c215567..10e62bc 100644
--- a/wpa_supplicant/systemd/wpa_supplicant@.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -10,4 +10,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant@%i.service
diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c
index deb19f6..f60b182 100644
--- a/wpa_supplicant/tests/test_eap_sim_common.c
+++ b/wpa_supplicant/tests/test_eap_sim_common.c
@@ -2,14 +2,8 @@
* Test program for EAP-SIM PRF
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "eap_common/eap_sim_common.c"
@@ -34,7 +28,7 @@ static int test_eap_sim_prf(void)
printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w) != 0)) {
+ if (memcmp(w, buf, sizeof(w)) != 0) {
printf("eap_sim_prf failed\n");
return 1;
}
diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c
index 7947137..39971f2 100644
--- a/wpa_supplicant/tests/test_wpa.c
+++ b/wpa_supplicant/tests/test_wpa.c
@@ -2,14 +2,8 @@
* Test program for combined WPA authenticator/supplicant
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -20,11 +14,7 @@
#include "../config.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/wpa_ie.h"
-#include "../hostapd/wpa.h"
-
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
+#include "ap/wpa_auth.h"
struct wpa {
@@ -304,7 +294,7 @@ static int auth_init_group(struct wpa *wpa)
static int auth_init(struct wpa *wpa)
{
- wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr);
+ 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;
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
new file mode 100755
index 0000000..65e2fa1
--- /dev/null
+++ b/wpa_supplicant/utils/log2pcap.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012, Intel Corporation
+#
+# Author: Johannes Berg <johannes@sipsolutions.net>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import sys, struct, re
+
+def write_pcap_header(pcap_file):
+ pcap_file.write(
+ struct.pack('<IHHIIII',
+ 0xa1b2c3d4, 2, 4, 0, 0, 65535,
+ 105 # raw 802.11 format
+ ))
+
+def pcap_addpacket(pcap_file, ts, data):
+ # ts in seconds, float
+ pcap_file.write(struct.pack('<IIII',
+ int(ts), int(1000000 * ts) % 1000000,
+ len(data), len(data)))
+ pcap_file.write(data)
+
+if __name__ == "__main__":
+ try:
+ input = sys.argv[1]
+ pcap = sys.argv[2]
+ except IndexError:
+ print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+ sys.exit(2)
+
+ input_file = open(input, 'r')
+ pcap_file = open(pcap, 'w')
+ frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)')
+
+ write_pcap_header(pcap_file)
+
+ for line in input_file:
+ m = frame_re.match(line)
+ if m is None:
+ continue
+ if m.group(2):
+ ts = float(m.group(2))
+ else:
+ ts = 0
+ hexdata = m.group(3)
+ hexdata = hexdata.split()
+ data = ''.join([chr(int(x, 16)) for x in hexdata])
+ pcap_addpacket(pcap_file, ts, data)
+
+ input_file.close()
+ pcap_file.close()
diff --git a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
index 38b29c4..af7b3fe 100755
--- a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
+++ b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
@@ -411,6 +411,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"
>
</File>
diff --git a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
index b107842..97aa2c5 100755
--- a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
+++ b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
@@ -206,6 +206,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"
>
</File>
diff --git a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
index e3886b7..51acab9 100755
--- a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
+++ b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
@@ -399,6 +399,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"
>
</File>
diff --git a/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
index 1034891..6fd8af8 100755
--- a/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
+++ b/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
@@ -399,6 +399,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"
>
</File>
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
new file mode 100644
index 0000000..578199e
--- /dev/null
+++ b/wpa_supplicant/wifi_display.c
@@ -0,0 +1,292 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wifi_display.h"
+
+
+#define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
+
+
+int wifi_display_init(struct wpa_global *global)
+{
+ global->wifi_display = 1;
+ return 0;
+}
+
+
+void wifi_display_deinit(struct wpa_global *global)
+{
+ int i;
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ wpabuf_free(global->wfd_subelem[i]);
+ global->wfd_subelem[i] = NULL;
+ }
+}
+
+
+static int wifi_display_update_wfd_ie(struct wpa_global *global)
+{
+ struct wpabuf *ie, *buf;
+ size_t len, plen;
+
+ wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
+
+ if (!global->wifi_display) {
+ wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
+ "include WFD IE");
+ p2p_set_wfd_ie_beacon(global->p2p, NULL);
+ p2p_set_wfd_ie_probe_req(global->p2p, NULL);
+ p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
+ p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
+ p2p_set_wfd_ie_invitation(global->p2p, NULL);
+ p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
+ p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
+ p2p_set_wfd_ie_go_neg(global->p2p, NULL);
+ p2p_set_wfd_dev_info(global->p2p, NULL);
+ p2p_set_wfd_assoc_bssid(global->p2p, NULL);
+ p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
+ return 0;
+ }
+
+ p2p_set_wfd_dev_info(global->p2p,
+ global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ p2p_set_wfd_assoc_bssid(
+ global->p2p,
+ global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
+ p2p_set_wfd_coupled_sink_info(
+ global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+ /*
+ * WFD IE is included in number of management frames. Two different
+ * sets of subelements are included depending on the frame:
+ *
+ * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
+ * Provision Discovery Req:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ *
+ * Probe Request:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Extended Capability]
+ *
+ * Probe Response:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Extended Capability]
+ * [WFD Session Info]
+ *
+ * (Re)Association Response, P2P Invitation Req/Resp,
+ * Provision Discovery Resp:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Session Info]
+ */
+ len = 0;
+ if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_DEVICE_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_ASSOCIATED_BSSID]);
+ if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_COUPLED_SINK]);
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_SESSION_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+ len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+ wpabuf_put_buf(buf, global->wfd_subelem[
+ WFD_SUBELEM_ASSOCIATED_BSSID]);
+ if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
+ p2p_set_wfd_ie_beacon(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
+ ie);
+ p2p_set_wfd_ie_assoc_req(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
+ p2p_set_wfd_ie_go_neg(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+ "Request", ie);
+ p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
+
+ plen = buf->used;
+ if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
+ p2p_set_wfd_ie_probe_req(global->p2p, ie);
+
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
+ p2p_set_wfd_ie_probe_resp(global->p2p, ie);
+
+ /* Remove WFD Extended Capability from buffer */
+ buf->used = plen;
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
+ p2p_set_wfd_ie_invitation(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+ "Response", ie);
+ p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
+
+ wpabuf_free(buf);
+
+ return 0;
+}
+
+
+void wifi_display_enable(struct wpa_global *global, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
+ enabled ? "enabled" : "disabled");
+ global->wifi_display = enabled;
+ wifi_display_update_wfd_ie(global);
+}
+
+
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
+{
+ char *pos;
+ int subelem;
+ size_t len;
+ struct wpabuf *e;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ if (len == 0) {
+ /* Clear subelement */
+ e = NULL;
+ wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
+ } else {
+ e = wpabuf_alloc(1 + len);
+ if (e == NULL)
+ return -1;
+ wpabuf_put_u8(e, subelem);
+ if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+ wpabuf_free(e);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
+ }
+
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = e;
+ wifi_display_update_wfd_ie(global);
+
+ return 0;
+}
+
+
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+ char *buf, size_t buflen)
+{
+ int subelem;
+
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
+ if (global->wfd_subelem[subelem] == NULL)
+ return 0;
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(global->wfd_subelem[subelem]) +
+ 1,
+ wpabuf_len(global->wfd_subelem[subelem]) - 1);
+}
+
+
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
+{
+ char *subelem = NULL;
+ const u8 *buf;
+ size_t buflen;
+ size_t i = 0;
+ u16 elen;
+
+ if (!wfd_subelems)
+ return NULL;
+
+ buf = wpabuf_head_u8(wfd_subelems);
+ if (!buf)
+ return NULL;
+
+ buflen = wpabuf_len(wfd_subelems);
+
+ while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
+ elen = WPA_GET_BE16(buf + i + 1);
+
+ if (buf[i] == id) {
+ subelem = os_zalloc(2 * elen + 1);
+ if (!subelem)
+ return NULL;
+ wpa_snprintf_hex(subelem, 2 * elen + 1,
+ buf + i +
+ WIFI_DISPLAY_SUBELEM_HEADER_LEN,
+ elen);
+ break;
+ }
+
+ i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
+ }
+
+ return subelem;
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
new file mode 100644
index 0000000..7554817
--- /dev/null
+++ b/wpa_supplicant/wifi_display.h
@@ -0,0 +1,21 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WIFI_DISPLAY_H
+#define WIFI_DISPLAY_H
+
+int wifi_display_init(struct wpa_global *global);
+void wifi_display_deinit(struct wpa_global *global);
+void wifi_display_enable(struct wpa_global *global, int enabled);
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+ char *buf, size_t buflen);
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id);
+
+#endif /* WIFI_DISPLAY_H */
diff --git a/wpa_supplicant/win_if_list.c b/wpa_supplicant/win_if_list.c
index 0e1532e..39634d9 100644
--- a/wpa_supplicant/win_if_list.c
+++ b/wpa_supplicant/win_if_list.c
@@ -2,14 +2,8 @@
* win_if_list - Display network interfaces with description (for Windows)
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This small tool is for the Windows build to provide an easy way of fetching
* a list of available network interfaces.
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
new file mode 100644
index 0000000..65b2783
--- /dev/null
+++ b/wpa_supplicant/wnm_sta.c
@@ -0,0 +1,789 @@
+/*
+ * wpa_supplicant - WNM
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "rsn_supp/wpa.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "ctrl_iface.h"
+#include "bss.h"
+#include "wnm_sta.h"
+
+#define MAX_TFS_IE_LEN 1024
+#define WNM_MAX_NEIGHBOR_REPORT 10
+
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
+ u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+ return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
+ const u8 *addr, u8 *buf, u16 *buf_len,
+ enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+ return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.request */
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+ u8 action, u16 intval, struct wpabuf *tfs_req)
+{
+ struct ieee80211_mgmt *mgmt;
+ int res;
+ size_t len;
+ struct wnm_sleep_element *wnmsleep_ie;
+ u8 *wnmtfs_ie;
+ u8 wnmsleep_ie_len;
+ u16 wnmtfs_ie_len; /* possibly multiple IE(s) */
+ enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
+ WNM_SLEEP_TFS_REQ_IE_NONE;
+
+ wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
+ "action=%s to " MACSTR,
+ action == 0 ? "enter" : "exit",
+ MAC2STR(wpa_s->bssid));
+
+ /* WNM-Sleep Mode IE */
+ wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+ wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
+ if (wnmsleep_ie == NULL)
+ return -1;
+ wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
+ wnmsleep_ie->len = wnmsleep_ie_len - 2;
+ wnmsleep_ie->action_type = action;
+ wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
+ wnmsleep_ie->intval = host_to_le16(intval);
+ wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
+ (u8 *) wnmsleep_ie, wnmsleep_ie_len);
+
+ /* TFS IE(s) */
+ if (tfs_req) {
+ wnmtfs_ie_len = wpabuf_len(tfs_req);
+ wnmtfs_ie = os_malloc(wnmtfs_ie_len);
+ if (wnmtfs_ie == NULL) {
+ os_free(wnmsleep_ie);
+ return -1;
+ }
+ os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
+ } else {
+ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+ if (wnmtfs_ie == NULL) {
+ os_free(wnmsleep_ie);
+ return -1;
+ }
+ if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
+ tfs_oper)) {
+ wnmtfs_ie_len = 0;
+ os_free(wnmtfs_ie);
+ wnmtfs_ie = NULL;
+ }
+ }
+ wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
+ (u8 *) wnmtfs_ie, wnmtfs_ie_len);
+
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+ if (mgmt == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+ "WNM-Sleep Request action frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
+ mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
+ wnmsleep_ie_len);
+ /* copy TFS IE here */
+ if (wnmtfs_ie_len > 0) {
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+ wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
+ }
+
+ len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
+ wnmtfs_ie_len;
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
+ "(action=%d, intval=%d)", action, intval);
+
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+
+ return res;
+}
+
+
+static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
+ u8 *tfsresp_ie_start,
+ u8 *tfsresp_ie_end)
+{
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
+ wpa_s->bssid, NULL, NULL);
+ /* remove GTK/IGTK ?? */
+
+ /* set the TFS Resp IE(s) */
+ if (tfsresp_ie_start && tfsresp_ie_end &&
+ tfsresp_ie_end - tfsresp_ie_start >= 0) {
+ u16 tfsresp_ie_len;
+ tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
+ tfsresp_ie_start;
+ wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
+ /* pass the TFS Resp IE(s) to driver for processing */
+ if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
+ tfsresp_ie_start,
+ &tfsresp_ie_len,
+ WNM_SLEEP_TFS_RESP_IE_SET))
+ wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
+ }
+}
+
+
+static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
+ const u8 *frm, u16 key_len_total)
+{
+ u8 *ptr, *end;
+ u8 gtk_len;
+
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid,
+ NULL, NULL);
+
+ /* Install GTK/IGTK */
+
+ /* point to key data field */
+ ptr = (u8 *) frm + 1 + 2;
+ 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) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
+ "length");
+ if (end > ptr) {
+ wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
+ ptr, end - ptr);
+ }
+ break;
+ }
+ if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
+ if (ptr[1] < 11 + 5) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
+ "subelem");
+ break;
+ }
+ gtk_len = *(ptr + 4);
+ if (ptr[1] < 11 + gtk_len ||
+ gtk_len < 5 || gtk_len > 32) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
+ "subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(
+ wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_GTK,
+ ptr);
+ ptr += 13 + gtk_len;
+#ifdef CONFIG_IEEE80211W
+ } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
+ if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
+ "subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_IGTK, ptr);
+ ptr += 10 + WPA_IGTK_LEN;
+#endif /* CONFIG_IEEE80211W */
+ } else
+ break; /* skip the loop */
+ }
+}
+
+
+static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
+ const u8 *frm, int len)
+{
+ /*
+ * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
+ * WNM-Sleep Mode IE | TFS Response IE
+ */
+ u8 *pos = (u8 *) frm; /* point to payload after the action field */
+ u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
+ struct wnm_sleep_element *wnmsleep_ie = NULL;
+ /* multiple TFS Resp IE (assuming consecutive) */
+ u8 *tfsresp_ie_start = NULL;
+ u8 *tfsresp_ie_end = NULL;
+
+ wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
+ frm[0], key_len_total);
+ pos += 3 + key_len_total;
+ if (pos > frm + len) {
+ wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
+ return;
+ }
+ while (pos - frm < len) {
+ u8 ie_len = *(pos + 1);
+ if (pos + 2 + ie_len > frm + len) {
+ 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)
+ wnmsleep_ie = (struct wnm_sleep_element *) pos;
+ else if (*pos == WLAN_EID_TFS_RESP) {
+ if (!tfsresp_ie_start)
+ tfsresp_ie_start = pos;
+ tfsresp_ie_end = pos;
+ } else
+ wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+ pos += ie_len + 2;
+ }
+
+ if (!wnmsleep_ie) {
+ wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+ return;
+ }
+
+ if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
+ wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
+ wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
+ "frame (action=%d, intval=%d)",
+ wnmsleep_ie->action_type, wnmsleep_ie->intval);
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
+ wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
+ tfsresp_ie_end);
+ } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
+ wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
+ "(action=%d, intval=%d)",
+ wnmsleep_ie->action_type, wnmsleep_ie->intval);
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
+ wpa_s->bssid, NULL, NULL);
+ else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
+ wpa_s->bssid, NULL, NULL);
+ }
+}
+
+
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].bearing);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
+ }
+
+ os_free(wpa_s->wnm_neighbor_report_elements);
+ wpa_s->wnm_neighbor_report_elements = NULL;
+}
+
+
+static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
+ u8 id, u8 elen, const u8 *pos)
+{
+ switch (id) {
+ case WNM_NEIGHBOR_TSF:
+ if (elen < 2 + 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
+ break;
+ }
+ rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
+ if (rep->tsf_info == NULL)
+ break;
+ rep->tsf_info->present = 1;
+ os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
+ os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
+ break;
+ case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
+ "country string");
+ break;
+ }
+ rep->con_coun_str =
+ os_zalloc(sizeof(struct condensed_country_string));
+ if (rep->con_coun_str == NULL)
+ break;
+ rep->con_coun_str->present = 1;
+ os_memcpy(rep->con_coun_str->country_string, pos, 2);
+ break;
+ case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
+ if (elen < 1) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
+ "candidate");
+ break;
+ }
+ rep->bss_tran_can =
+ os_zalloc(sizeof(struct bss_transition_candidate));
+ if (rep->bss_tran_can == NULL)
+ break;
+ rep->bss_tran_can->present = 1;
+ rep->bss_tran_can->preference = pos[0];
+ break;
+ case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+ if (elen < 12) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
+ "duration");
+ break;
+ }
+ rep->bss_term_dur =
+ os_zalloc(sizeof(struct bss_termination_duration));
+ if (rep->bss_term_dur == NULL)
+ break;
+ rep->bss_term_dur->present = 1;
+ os_memcpy(rep->bss_term_dur->duration, pos, 12);
+ break;
+ case WNM_NEIGHBOR_BEARING:
+ if (elen < 8) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
+ "bearing");
+ break;
+ }
+ rep->bearing = os_zalloc(sizeof(struct bearing));
+ if (rep->bearing == NULL)
+ break;
+ rep->bearing->present = 1;
+ os_memcpy(rep->bearing->bearing, pos, 8);
+ break;
+ case WNM_NEIGHBOR_MEASUREMENT_PILOT:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
+ "pilot");
+ break;
+ }
+ rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
+ if (rep->meas_pilot == NULL)
+ break;
+ rep->meas_pilot->present = 1;
+ rep->meas_pilot->measurement_pilot = pos[0];
+ rep->meas_pilot->num_vendor_specific = pos[1];
+ os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2);
+ break;
+ case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
+ if (elen < 4) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
+ "capabilities");
+ break;
+ }
+ rep->rrm_cap =
+ os_zalloc(sizeof(struct rrm_enabled_capabilities));
+ if (rep->rrm_cap == NULL)
+ break;
+ rep->rrm_cap->present = 1;
+ os_memcpy(rep->rrm_cap->capabilities, pos, 4);
+ break;
+ case WNM_NEIGHBOR_MULTIPLE_BSSID:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
+ break;
+ }
+ rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
+ if (rep->mul_bssid == NULL)
+ break;
+ rep->mul_bssid->present = 1;
+ rep->mul_bssid->max_bssid_indicator = pos[0];
+ rep->mul_bssid->num_vendor_specific = pos[1];
+ os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2);
+ break;
+ }
+}
+
+
+static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
+ const u8 *pos, u8 len,
+ struct neighbor_report *rep)
+{
+ u8 left = len;
+
+ if (left < 13) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
+ return;
+ }
+
+ os_memcpy(rep->bssid, pos, ETH_ALEN);
+ os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4);
+ rep->regulatory_class = *(pos + 10);
+ rep->channel_number = *(pos + 11);
+ rep->phy_type = *(pos + 12);
+
+ pos += 13;
+ left -= 13;
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ wnm_parse_neighbor_report_elem(rep, id, elen, pos);
+ left -= 2 + elen;
+ pos += elen;
+ }
+}
+
+
+static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res,
+ struct neighbor_report *neigh_rep,
+ u8 num_neigh_rep, u8 *bssid_to_connect)
+{
+
+ u8 i, j;
+
+ if (scan_res == NULL || num_neigh_rep == 0)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
+ MAC2STR(wpa_s->bssid),
+ wpa_s->current_bss ? wpa_s->current_bss->level : 0);
+
+ for (i = 0; i < num_neigh_rep; i++) {
+ for (j = 0; j < scan_res->num; j++) {
+ /* Check for a better RSSI AP */
+ if (os_memcmp(scan_res->res[j]->bssid,
+ neigh_rep[i].bssid, ETH_ALEN) == 0 &&
+ scan_res->res[j]->level >
+ wpa_s->current_bss->level) {
+ /* Got a BSSID with better RSSI value */
+ os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
+ ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR
+ " with better scan RSSI %d",
+ MAC2STR(scan_res->res[j]->bssid),
+ scan_res->res[j]->level);
+ return 1;
+ }
+ wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR
+ " RSSI %d", j,
+ MAC2STR(scan_res->res[j]->bssid),
+ scan_res->res[j]->level);
+ }
+ }
+
+ return 0;
+}
+
+
+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;
+ struct ieee80211_mgmt *mgmt;
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
+ "to " MACSTR " dialog_token=%u status=%u delay=%d",
+ MAC2STR(wpa_s->bssid), dialog_token, status, delay);
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ os_memset(&buf, 0, sizeof(buf));
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
+ mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
+ mgmt->u.action.u.bss_tm_resp.status_code = status;
+ mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
+ pos = mgmt->u.action.u.bss_tm_resp.variable;
+ if (target_bssid) {
+ os_memcpy(pos, target_bssid, ETH_ALEN);
+ pos += ETH_ALEN;
+ } else if (status == WNM_BSS_TM_ACCEPT) {
+ /*
+ * P802.11-REVmc clarifies that the Target BSSID field is always
+ * present when status code is zero, so use a fake value here if
+ * no BSSID is yet known.
+ */
+ os_memset(pos, 0, ETH_ALEN);
+ pos += ETH_ALEN;
+ }
+
+ len = pos - (u8 *) &mgmt->u.action.category;
+
+ wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+}
+
+
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ u8 bssid[ETH_ALEN];
+
+ if (scan_res == NULL) {
+ wpa_printf(MSG_ERROR, "Scan result is NULL");
+ goto send_bss_resp_fail;
+ }
+
+ /* Compare the Neighbor Report and scan results */
+ if (compare_scan_neighbor_results(wpa_s, scan_res,
+ wpa_s->wnm_neighbor_report_elements,
+ wpa_s->wnm_num_neighbor_report,
+ bssid) == 1) {
+ /* Associate to the network */
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "WNM: Target AP not found from "
+ "BSS table");
+ goto send_bss_resp_fail;
+ }
+
+ /* Send the BSS Management Response - Accept */
+ if (wpa_s->wnm_reply) {
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ WNM_BSS_TM_ACCEPT,
+ 0, bssid);
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ wnm_deallocate_memory(wpa_s);
+ return;
+ }
+
+ /* Send reject response for all the failures */
+send_bss_resp_fail:
+ wnm_deallocate_memory(wpa_s);
+ if (wpa_s->wnm_reply) {
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ WNM_BSS_TM_REJECT_UNSPECIFIED,
+ 0, NULL);
+ }
+ return;
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
+ const u8 *pos, const u8 *end,
+ int reply)
+{
+ if (pos + 5 > end)
+ return;
+
+ wpa_s->wnm_dialog_token = pos[0];
+ wpa_s->wnm_mode = pos[1];
+ wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
+ wpa_s->wnm_validity_interval = pos[4];
+ wpa_s->wnm_reply = reply;
+
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
+ "dialog_token=%u request_mode=0x%x "
+ "disassoc_timer=%u validity_interval=%u",
+ wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
+ wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval);
+
+ pos += 5;
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ if (pos + 12 > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
+ return;
+ }
+ os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
+ pos += 12; /* BSS Termination Duration */
+ }
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
+ char url[256];
+ unsigned int beacon_int;
+
+ if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
+ "Management Request (URL)");
+ return;
+ }
+ os_memcpy(url, pos + 1, pos[0]);
+ url[pos[0]] = '\0';
+ pos += 1 + pos[0];
+
+ if (wpa_s->current_bss)
+ beacon_int = wpa_s->current_bss->beacon_int;
+ else
+ beacon_int = 100; /* best guess */
+
+ wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
+ wpa_sm_pmf_enabled(wpa_s->wpa),
+ wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
+ }
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
+ "Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
+ if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
+ /* TODO: mark current BSS less preferred for
+ * selection */
+ wpa_printf(MSG_DEBUG, "Trying to find another BSS");
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+ }
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
+ wpa_s->wnm_num_neighbor_report = 0;
+ os_free(wpa_s->wnm_neighbor_report_elements);
+ wpa_s->wnm_neighbor_report_elements = os_zalloc(
+ WNM_MAX_NEIGHBOR_REPORT *
+ sizeof(struct neighbor_report));
+ if (wpa_s->wnm_neighbor_report_elements == NULL)
+ return;
+
+ while (pos + 2 <= end &&
+ wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
+ {
+ u8 tag = *pos++;
+ u8 len = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
+ tag);
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+ return;
+ }
+ wnm_parse_neighbor_report(
+ wpa_s, pos, len,
+ &wpa_s->wnm_neighbor_report_elements[
+ wpa_s->wnm_num_neighbor_report]);
+
+ pos += len;
+ wpa_s->wnm_num_neighbor_report++;
+ }
+
+ wpa_s->scan_res_handler = wnm_scan_response;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (reply) {
+ enum bss_trans_mgmt_status_code status;
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+ status = WNM_BSS_TM_ACCEPT;
+ else {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
+ status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+ }
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ status, 0, NULL);
+ }
+}
+
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason)
+{
+ u8 buf[1000], *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);
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ os_memset(&buf, 0, sizeof(buf));
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
+ mgmt->u.action.u.bss_tm_query.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
+ pos = mgmt->u.action.u.bss_tm_query.variable;
+
+ len = pos - (u8 *) &mgmt->u.action.category;
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+
+ return ret;
+}
+
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ const u8 *pos, *end;
+ u8 act;
+
+ if (len < IEEE80211_HDRLEN + 2)
+ return;
+
+ pos = &mgmt->u.action.category;
+ pos++;
+ act = *pos++;
+ end = ((const u8 *) mgmt) + len;
+
+ wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
+ act, MAC2STR(mgmt->sa));
+ if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+ os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
+ "frame");
+ return;
+ }
+
+ switch (act) {
+ case WNM_BSS_TRANS_MGMT_REQ:
+ ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
+ !(mgmt->da[0] & 0x01));
+ break;
+ case WNM_SLEEP_MODE_RESP:
+ ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "WNM: Unknown request");
+ break;
+ }
+}
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
new file mode 100644
index 0000000..de87301
--- /dev/null
+++ b/wpa_supplicant/wnm_sta.h
@@ -0,0 +1,87 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_STA_H
+#define WNM_STA_H
+
+struct tsf_info {
+ u8 present;
+ u8 tsf_offset[2];
+ u8 beacon_interval[2];
+};
+
+struct condensed_country_string {
+ u8 present;
+ u8 country_string[2];
+};
+
+struct bss_transition_candidate {
+ u8 present;
+ u8 preference;
+};
+
+struct bss_termination_duration {
+ u8 present;
+ u8 duration[12];
+};
+
+struct bearing {
+ u8 present;
+ u8 bearing[8];
+};
+
+struct measurement_pilot {
+ u8 present;
+ u8 measurement_pilot;
+ u8 num_vendor_specific;
+ u8 vendor_specific[255];
+};
+
+struct rrm_enabled_capabilities {
+ u8 present;
+ u8 capabilities[4];
+};
+
+struct multiple_bssid {
+ u8 present;
+ u8 max_bssid_indicator;
+ u8 num_vendor_specific;
+ u8 vendor_specific[255];
+};
+
+struct neighbor_report {
+ u8 bssid[ETH_ALEN];
+ u8 bssid_information[4];
+ u8 regulatory_class;
+ u8 channel_number;
+ u8 phy_type;
+ struct tsf_info *tsf_info;
+ struct condensed_country_string *con_coun_str;
+ struct bss_transition_candidate *bss_tran_can;
+ struct bss_termination_duration *bss_term_dur;
+ struct bearing *bearing;
+ struct measurement_pilot *meas_pilot;
+ struct rrm_enabled_capabilities *rrm_cap;
+ struct multiple_bssid *mul_bssid;
+};
+
+
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+ u8 action, u16 intval, struct wpabuf *tfs_req);
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len);
+
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason);
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+
+#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 7da13c3..d66e864 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -26,6 +20,7 @@
#include "utils/edit.h"
#include "utils/list.h"
#include "common/version.h"
+#include "common/ieee802_11_defs.h"
#ifdef ANDROID
#include <cutils/properties.h>
#endif /* ANDROID */
@@ -33,32 +28,15 @@
static const char *wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
static const char *wpa_cli_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n";
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
static const char *wpa_cli_full_license =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
-"GNU General Public License for more details.\n"
-"\n"
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license.\n"
+"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"
@@ -92,7 +70,7 @@ static struct wpa_ctrl *ctrl_conn;
static struct wpa_ctrl *mon_conn;
static int wpa_cli_quit = 0;
static int wpa_cli_attached = 0;
-static int wpa_cli_connected = 0;
+static int wpa_cli_connected = -1;
static int wpa_cli_last_id = 0;
#ifndef CONFIG_CTRL_IFACE_DIR
#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
@@ -103,6 +81,7 @@ static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
+static char *ifname_prefix = NULL;
struct cli_txt_entry {
struct dl_list list;
@@ -112,10 +91,14 @@ struct cli_txt_entry {
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 */
+static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
-static void print_help(void);
+static void print_help(const char *cmd);
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
+static void wpa_cli_close_connection(void);
+static char * wpa_cli_get_default_ifname(void);
+static char ** wpa_list_cmd_list(void);
static void usage(void)
@@ -132,7 +115,7 @@ static void usage(void)
" -B = run a daemon in the background\n"
" default path: " CONFIG_CTRL_IFACE_DIR "\n"
" default interface: first interface found in socket path\n");
- print_help();
+ print_help(NULL);
}
@@ -192,11 +175,9 @@ static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
end = os_strchr(txt, ' ');
if (end == NULL)
end = txt + os_strlen(txt);
- buf = os_malloc(end - txt + 1);
+ buf = dup_binstr(txt, end - txt);
if (buf == NULL)
return;
- os_memcpy(buf, txt, end - txt);
- buf[end - txt] = '\0';
cli_txt_list_del(txt_list, buf);
os_free(buf);
}
@@ -242,11 +223,9 @@ static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
end = os_strchr(txt, ' ');
if (end == NULL)
end = txt + os_strlen(txt);
- buf = os_malloc(end - txt + 1);
+ buf = dup_binstr(txt, end - txt);
if (buf == NULL)
return -1;
- os_memcpy(buf, txt, end - txt);
- buf[end - txt] = '\0';
ret = cli_txt_list_add(txt_list, buf);
os_free(buf);
return ret;
@@ -260,7 +239,7 @@ static char ** cli_txt_list_array(struct dl_list *txt_list)
char **res;
struct cli_txt_entry *e;
- res = os_zalloc((count + 1) * sizeof(char *));
+ res = os_calloc(count + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -383,6 +362,7 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
} else {
printf("Warning: Failed to attach to "
"wpa_supplicant.\n");
+ wpa_cli_close_connection();
return -1;
}
}
@@ -418,7 +398,7 @@ static void wpa_cli_msg_cb(char *msg, size_t len)
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
{
- char buf[2048];
+ char buf[4096];
size_t len;
int ret;
@@ -426,6 +406,12 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
printf("Not connected to wpa_supplicant - 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);
@@ -452,10 +438,67 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
}
+static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+ char *argv[])
+{
+ int i, res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos, "%s", cmd);
+ if (res < 0 || res >= end - pos)
+ goto fail;
+ pos += res;
+
+ for (i = 0; i < argc; i++) {
+ res = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (res < 0 || res >= end - pos)
+ goto fail;
+ pos += res;
+ }
+
+ buf[buflen - 1] = '\0';
+ return 0;
+
+fail:
+ printf("Too long command\n");
+ return -1;
+}
+
+
+static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
+ int argc, char *argv[])
+{
+ char buf[4096];
+ if (argc < min_args) {
+ printf("Invalid %s command - at least %d argument%s "
+ "required.\n", cmd, min_args,
+ min_args > 1 ? "s are" : " is");
+ return -1;
+ }
+ if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "IFNAME");
+}
+
+
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
- return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
+ if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
+ if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-WPS");
+ if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
+ return wpa_ctrl_command(ctrl, "STATUS");
}
@@ -473,14 +516,7 @@ static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int ret;
- if (argc == 0)
- return -1;
- ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]);
- if (ret < 0 || (size_t) ret >= sizeof(cmd))
- return -1;
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
}
@@ -498,11 +534,26 @@ static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- print_help();
+ print_help(argc > 0 ? argv[0] : NULL);
return 0;
}
+static char ** wpa_cli_complete_help(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = wpa_list_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
@@ -519,72 +570,90 @@ static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static void wpa_cli_show_variables(void)
-{
- printf("set variables:\n"
- " EAPOL::heldPeriod (EAPOL state machine held period, "
- "in seconds)\n"
- " EAPOL::authPeriod (EAPOL state machine authentication "
- "period, in seconds)\n"
- " EAPOL::startPeriod (EAPOL state machine start period, in "
- "seconds)\n"
- " EAPOL::maxStart (EAPOL state machine maximum start "
- "attempts)\n");
- printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
- "seconds)\n"
- " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
- " threshold\n\tpercentage)\n"
- " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
- "security\n\tassociation in seconds)\n");
-}
-
-
static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
- if (argc == 0) {
- wpa_cli_show_variables();
- return 0;
+ if (argc == 1) {
+ res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long SET command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
}
- if (argc != 1 && argc != 2) {
- printf("Invalid SET command: needs two arguments (variable "
- "name and value)\n");
- return -1;
- }
+ return wpa_cli_cmd(ctrl, "SET", 2, argc, argv);
+}
- if (argc == 1)
- res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET command.\n");
- return -1;
+
+static char ** wpa_cli_complete_set(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ /* runtime values */
+ "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod",
+ "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime",
+ "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout",
+ "wps_fragment_size", "wps_version_number", "ampdu",
+ "tdls_testing", "tdls_disabled", "pno", "radio_disabled",
+ "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
+ "no_keep_alive",
+ /* global configuration parameters */
+ "eapol_version", "ap_scan", "disable_scan_offload",
+ "fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
+ "pkcs11_module_path", "pcsc_reader", "pcsc_pin",
+ "driver_param", "dot11RSNAConfigPMKLifetime",
+ "dot11RSNAConfigPMKReauthThreshold",
+ "dot11RSNAConfigSATimeout",
+ "update_config", "load_dynamic_eap", "uuid", "device_name",
+ "manufacturer", "model_name", "model_number", "serial_number",
+ "device_type", "os_version", "config_methods",
+ "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+ "p2p_listen_reg_class", "p2p_listen_channel",
+ "p2p_oper_reg_class", "p2p_oper_channel",
+ "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
+ "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+ "p2p_no_go_freq",
+ "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
+ "p2p_go_vht",
+ "p2p_ignore_shared_freq", "country", "bss_max_count",
+ "bss_expiration_age", "bss_expiration_scan_count",
+ "filter_ssids", "filter_rssi", "max_num_sta",
+ "disassoc_low_ack", "hs20", "interworking", "hessid",
+ "access_network_type", "pbc_in_m1", "autoscan",
+ "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
+ "wps_nfc_dev_pw", "ext_password_backend",
+ "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+ "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
+ "ignore_old_scan_res", "freq_list", "external_sim",
+ "tdls_external_control"
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **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;
+ }
+ return res;
}
- return wpa_ctrl_command(ctrl, cmd);
+
+ if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0)
+ return cli_txt_list_array(&bsses);
+
+ return NULL;
}
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid GET command: need one argument (variable "
- "name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long GET command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
}
@@ -610,97 +679,48 @@ static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid PREAUTH command: needs one argument "
- "(BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long PREAUTH command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
}
static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid AP_SCAN command: needs one argument (ap_scan "
- "value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long AP_SCAN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
}
static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid SCAN_INTERVAL command: needs one argument "
- "scan_interval value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "SCAN_INTERVAL %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SCAN_INTERVAL command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
}
static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid BSS_EXPIRE_AGE command: needs one argument "
- "(bss_expire_age value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_AGE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long BSS_EXPIRE_AGE command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
}
static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
+ return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
char cmd[256];
int res;
- if (argc != 1) {
- printf("Invalid BSS_EXPIRE_COUNT command: needs one argument "
- "(bss_expire_count value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_COUNT %s", argv[0]);
+ if (argc < 1)
+ res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long BSS_EXPIRE_COUNT command.\n");
+ printf("Too long BSS_FLUSH command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
@@ -710,69 +730,24 @@ static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid STKSTART command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long STKSTART command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
}
static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid FT_DS command: needs one argument "
- "(Target AP MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long FT_DS command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
}
static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc == 0) {
- /* Any BSSID */
- return wpa_ctrl_command(ctrl, "WPS_PBC");
- }
-
- /* Specific BSSID */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PBC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
}
static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
printf("Invalid WPS_PIN command: need one or two arguments:\n"
"- BSSID: use 'any' to select any\n"
@@ -781,90 +756,145 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
return -1;
}
- if (argc == 1) {
- /* Use dynamically generated PIN (returned as reply) */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
- }
-
- /* Use hardcoded PIN from a label */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
}
static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
+ return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
+}
- if (argc != 1 && argc != 2) {
- printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
- "- PIN to be verified\n");
+
+static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_tag_read' command - one argument "
+ "is required.\n");
return -1;
}
- if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_CHECK_PIN command.\n");
+ buflen = 18 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
}
-static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+ return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
}
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[256];
- int res;
+ return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
- if (argc != 3 && argc != 4) {
- printf("Invalid WPS_OOB command: need three or four "
- "arguments:\n"
- "- DEV_TYPE: use 'ufd' or 'nfc'\n"
- "- PATH: path of OOB device like '/mnt'\n"
- "- METHOD: OOB method 'pin-e' or 'pin-r', "
- "'cred'\n"
- "- DEV_NAME: (only for NFC) device name like "
- "'pn531'\n");
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'nfc_rx_handover_req' command - one argument "
+ "is required.\n");
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_OOB command.\n");
+ buflen = 21 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+ "is required.\n");
return -1;
}
- return wpa_ctrl_command(ctrl, cmd);
+
+ buflen = 21 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
}
-#endif /* CONFIG_WPS_OOB */
+
+
+static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
+}
+
+#endif /* CONFIG_WPS_NFC */
static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -927,41 +957,14 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc < 1) {
- printf("Invalid WPS_AP_PIN command: needs at least one "
- "argument\n");
- return -1;
- }
-
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_AP_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
}
static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- if (argc > 0) {
- os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]);
- return wpa_ctrl_command(ctrl, cmd);
- }
- return wpa_ctrl_command(ctrl, "WPS_ER_START");
+ return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
}
@@ -976,9 +979,6 @@ static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc < 2) {
printf("Invalid WPS_ER_PIN command: need at least two "
"arguments:\n"
@@ -988,48 +988,20 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
}
static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid WPS_ER_PBC command: need one argument:\n"
- "- UUID: Specify the Enrollee\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_PBC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
}
static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
"- UUID: specify which AP to use\n"
@@ -1037,22 +1009,13 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_LEARN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
}
static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_SET_CONFIG command: need two "
"arguments:\n"
@@ -1061,13 +1024,7 @@ static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_SET_CONFIG %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_SET_CONFIG command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
}
@@ -1122,42 +1079,32 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
}
-static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
+#ifdef CONFIG_WPS_NFC
+static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid IBSS_RSN command: needs one argument "
- "(Peer STA MAC address)\n");
+ if (argc != 2) {
+ printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
+ "arguments:\n"
+ "- WPS/NDEF: token format\n"
+ "- UUID: specify which AP to use\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long IBSS_RSN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
}
+#endif /* CONFIG_WPS_NFC */
-static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
+ return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid LEVEL command: needs one argument (debug "
- "level)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long LEVEL command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+
+static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
}
@@ -1326,63 +1273,63 @@ static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
int i, ret;
if (argc < 2) {
- printf("Invalid PASSPHRASE command: needs two arguments "
- "(network id and passphrase)\n");
+ printf("Invalid SIM command: needs two arguments "
+ "(network id and SIM operation response)\n");
return -1;
}
end = cmd + sizeof(cmd);
pos = cmd;
- ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
- printf("Too long PASSPHRASE command.\n");
+ printf("Too long SIM command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
- printf("Too long PASSPHRASE command.\n");
+ printf("Too long SIM command.\n");
return -1;
}
pos += ret;
}
-
return wpa_ctrl_command(ctrl, cmd);
}
-static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
char cmd[256], *pos, *end;
int i, ret;
if (argc < 2) {
- printf("Invalid BSSID command: needs two arguments (network "
- "id and BSSID)\n");
+ printf("Invalid PASSPHRASE command: needs two arguments "
+ "(network id and passphrase)\n");
return -1;
}
end = cmd + sizeof(cmd);
pos = cmd;
- ret = os_snprintf(pos, end - pos, "BSSID");
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
+ argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
- printf("Too long BSSID command.\n");
+ printf("Too long PASSPHRASE command.\n");
return -1;
}
pos += ret;
- for (i = 0; i < argc; i++) {
+ for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
- printf("Too long BSSID command.\n");
+ printf("Too long PASSPHRASE command.\n");
return -1;
}
pos += ret;
@@ -1392,55 +1339,27 @@ static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "BLACKLIST");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BLACKLIST command.\n");
+ if (argc < 2) {
+ printf("Invalid BSSID command: needs two arguments (network "
+ "id and BSSID)\n");
return -1;
}
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BLACKLIST command.\n");
- return -1;
- }
- pos += ret;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
}
-static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
+ return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
+}
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "LOG_LEVEL");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long LOG_LEVEL command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long LOG_LEVEL command.\n");
- return -1;
- }
- pos += ret;
- }
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
}
@@ -1454,63 +1373,21 @@ static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid SELECT_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
}
static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid ENABLE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
}
static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid DISABLE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
}
@@ -1524,21 +1401,7 @@ static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid REMOVE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
}
@@ -1566,36 +1429,24 @@ static void wpa_cli_show_network_variables(void)
static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
wpa_cli_show_network_variables();
return 0;
}
- if (argc != 3) {
+ if (argc < 3) {
printf("Invalid SET_NETWORK command: needs three arguments\n"
"(network id, variable name, and value)\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
- argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET_NETWORK command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
}
static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
wpa_cli_show_network_variables();
return 0;
@@ -1607,13 +1458,39 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long GET_NETWORK command.\n");
+ return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "LIST_CREDS");
+}
+
+
+static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ADD_CRED");
+}
+
+
+static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc != 3) {
+ printf("Invalid SET_CRED command: needs three arguments\n"
+ "(cred id, variable name, and value)\n");
return -1;
}
- return wpa_ctrl_command(ctrl, cmd);
+
+ return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
}
@@ -1640,7 +1517,7 @@ static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_ctrl_command(ctrl, "SCAN");
+ return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
}
@@ -1653,21 +1530,7 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[64];
- int res;
-
- if (argc != 1) {
- printf("Invalid BSS command: need one argument (index or "
- "BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
}
@@ -1689,9 +1552,6 @@ static char ** wpa_cli_complete_bss(const char *str, int pos)
static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[64];
- int res;
-
if (argc < 1 || argc > 2) {
printf("Invalid GET_CAPABILITY command: need either one or "
"two arguments\n");
@@ -1704,13 +1564,7 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
- (argc == 2) ? " strict" : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
}
@@ -1790,20 +1644,7 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid INTERFACE_REMOVE command: needs one argument "
- "(interface name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
}
@@ -1817,14 +1658,7 @@ static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
#ifdef CONFIG_AP
static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char buf[64];
- if (argc != 1) {
- printf("Invalid 'sta' command - exactly one argument, STA "
- "address, is required.\n");
- return -1;
- }
- os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
}
@@ -1840,7 +1674,7 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
return -1;
}
len = sizeof(buf) - 1;
- ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
@@ -1851,7 +1685,7 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
}
buf[len] = '\0';
- if (memcmp(buf, "FAIL", 4) == 0)
+ if (os_memcmp(buf, "FAIL", 4) == 0)
return -1;
printf("%s", buf);
@@ -1876,6 +1710,27 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
return -1;
}
+
+
+static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
+}
+
+static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
+}
+
#endif /* CONFIG_AP */
@@ -1899,21 +1754,7 @@ static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid ROAM command: needs one argument "
- "(target AP's BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long ROAM command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
}
@@ -1921,24 +1762,36 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[128];
- int res;
+ return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
+}
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_FIND");
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
+{
+ char **res = NULL;
+ int arg = get_cmd_arg_num(str, pos);
+
+ res = os_calloc(6, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ res[0] = os_strdup("type=social");
+ if (res[0] == NULL) {
+ os_free(res);
+ return NULL;
+ }
+ res[1] = os_strdup("type=progressive");
+ if (res[1] == NULL)
+ return res;
+ res[2] = os_strdup("delay=");
+ if (res[2] == NULL)
+ return res;
+ res[3] = os_strdup("dev_id=");
+ if (res[3] == NULL)
+ return res;
+ if (arg == 1)
+ res[4] = os_strdup("[timeout]");
+
+ return res;
}
@@ -1952,33 +1805,7 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc < 2) {
- printf("Invalid P2P_CONNECT command: needs at least two "
- "arguments (address and pbc/PIN)\n");
- return -1;
- }
-
- if (argc > 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_CONNECT %s %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3],
- argv[4]);
- else if (argc > 3)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
}
@@ -2000,37 +1827,14 @@ static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_LISTEN");
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_LISTEN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_GROUP_REMOVE command: needs one argument "
- "(interface name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
}
@@ -2052,31 +1856,13 @@ static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_GROUP_ADD");
-
- if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
if (argc != 2 && argc != 3) {
printf("Invalid P2P_PROV_DISC command: needs at least "
"two arguments, address and config method\n"
@@ -2084,16 +1870,7 @@ static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
}
@@ -2108,7 +1885,6 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[4096];
- int res;
if (argc != 2 && argc != 4) {
printf("Invalid P2P_SERV_DISC_REQ command: needs two "
@@ -2118,16 +1894,8 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERV_DISC_REQ %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
return -1;
- cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -2135,21 +1903,7 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_SERV_DISC_CANCEL_REQ command: needs one "
- "argument (pending request identifier)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_CANCEL_REQ %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
}
@@ -2184,21 +1938,7 @@ static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_SERV_DISC_EXTERNAL command: needs one "
- "argument (external processing: 0/1)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_EXTERNAL %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
}
@@ -2266,60 +2006,20 @@ static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_REJECT command: needs one argument "
- "(peer address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_REJECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc < 1) {
- printf("Invalid P2P_INVITE command: needs at least one "
- "argument\n");
- return -1;
- }
-
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char buf[64];
- if (argc != 1) {
- printf("Invalid 'p2p_peer' command - exactly one argument, "
- "P2P peer device address, is required.\n");
- return -1;
- }
- os_snprintf(buf, sizeof(buf), "P2P_PEER %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
}
@@ -2349,7 +2049,7 @@ static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
if (ctrl_conn == NULL)
return -1;
len = sizeof(buf) - 1;
- ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
@@ -2360,7 +2060,7 @@ static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
}
buf[len] = '\0';
- if (memcmp(buf, "FAIL", 4) == 0)
+ if (os_memcmp(buf, "FAIL", 4) == 0)
return -1;
pos = buf;
@@ -2395,20 +2095,51 @@ static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
+}
- if (argc != 2) {
- printf("Invalid P2P_SET command: needs two arguments (field, "
- "value)\n");
- return -1;
+
+static char ** wpa_cli_complete_p2p_set(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "discoverability",
+ "managed",
+ "listen_channel",
+ "ssid_postfix",
+ "noa",
+ "ps",
+ "oppps",
+ "ctwindow",
+ "disabled",
+ "conc_pref",
+ "force_long_sd",
+ "peer_filter",
+ "cross_connect",
+ "go_apsd",
+ "client_apsd",
+ "disallow_freq",
+ "disc_int",
+ "per_sta_psk",
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **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;
+ }
+ return res;
}
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SET %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0)
+ return cli_txt_list_array(&p2p_peers);
+
+ return NULL;
}
@@ -2428,48 +2159,65 @@ static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid P2P_UNAUTHORIZE command: needs one argument "
- "(peer address)\n");
+
+static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc != 0 && argc != 2 && argc != 4) {
+ printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
+ "(preferred duration, interval; in microsecods).\n"
+ "Optional second pair can be used to provide "
+ "acceptable values.\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "P2P_UNAUTHORIZE %s", argv[0]);
+ return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
+}
- if (res < 0 || (size_t) res >= sizeof(cmd))
+
+static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc != 0 && argc != 2) {
+ printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
+ "(availability period, availability interval; in "
+ "millisecods).\n"
+ "Extended Listen Timing can be cancelled with this "
+ "command when used without parameters.\n");
return -1;
+ }
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
}
-static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
+}
+
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
char cmd[100];
int res;
- if (argc != 0 && argc != 2 && argc != 4) {
- printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
- "(preferred duration, interval; in microsecods).\n"
- "Optional second pair can be used to provide "
- "acceptable values.\n");
+ if (argc != 1 && argc != 2) {
+ printf("Invalid WFD_SUBELEM_SET command: needs one or two "
+ "arguments (subelem, hexdump)\n");
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_PRESENCE_REQ %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ");
+ res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
+ argv[0], argc > 1 ? argv[1] : "");
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
@@ -2477,33 +2225,26 @@ static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
}
-static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
char cmd[100];
int res;
- if (argc != 0 && argc != 2) {
- printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
- "(availability period, availability interval; in "
- "millisecods).\n"
- "Extended Listen Timing can be cancelled with this "
- "command when used without parameters.\n");
+ if (argc != 1) {
+ printf("Invalid WFD_SUBELEM_GET command: needs one "
+ "argument (subelem)\n");
return -1;
}
- if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN");
+ res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
+ argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
-
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
@@ -2524,142 +2265,93 @@ static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
}
static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid INTERWORKING_CONNECT commands: needs one "
- "argument (BSSID)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
}
-static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
+}
- if (argc != 2) {
- printf("Invalid ANQP_GET command: needs two arguments "
- "(addr and info id list)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
}
#endif /* CONFIG_INTERWORKING */
-static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+#ifdef CONFIG_HS20
+
+static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[256];
- int res;
+ return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid STA_AUTOCONNECT command: needs one argument "
- "(0/1 = disable/enable automatic reconnection)\n");
+
+static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[512];
+
+ if (argc == 0) {
+ printf("Command needs one or two arguments (dst mac addr and "
+ "optional home realm)\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "STA_AUTOCONNECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long STA_AUTOCONNECT command.\n");
+
+ if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
+ argc, argv) < 0)
return -1;
- }
+
return wpa_ctrl_command(ctrl, cmd);
}
+#endif /* CONFIG_HS20 */
-static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+
+static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[256];
- int res;
+ return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid TDLS_DISCOVER command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_DISCOVER %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_DISCOVER command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_SETUP command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_SETUP %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_SETUP command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_TEARDOWN command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_TEARDOWN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
}
@@ -2670,6 +2362,77 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PKTCNT_POLL");
+}
+
+
+static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
+}
+
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc == 0)
+ return wpa_ctrl_command(ctrl, "AUTOSCAN ");
+
+ return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
+#ifdef CONFIG_WNM
+
+static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv);
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc == 0)
+ return -1;
+ return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
+#ifdef ANDROID
+static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
+}
+#endif /* ANDROID */
+
+
+static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "FLUSH");
+}
+
+
+static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2678,341 +2441,468 @@ enum wpa_cli_cmd_flags {
struct wpa_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+ char ** (*completion)(const char *str, int pos);
enum wpa_cli_cmd_flags flags;
const char *usage;
};
static struct wpa_cli_cmd wpa_cli_commands[] = {
- { "status", wpa_cli_cmd_status,
+ { "status", wpa_cli_cmd_status, NULL,
cli_cmd_flag_none,
"[verbose] = get current WPA/EAPOL/EAP status" },
- { "ping", wpa_cli_cmd_ping,
+ { "ifname", wpa_cli_cmd_ifname, NULL,
+ cli_cmd_flag_none,
+ "= get current interface name" },
+ { "ping", wpa_cli_cmd_ping, NULL,
cli_cmd_flag_none,
"= pings wpa_supplicant" },
- { "relog", wpa_cli_cmd_relog,
+ { "relog", wpa_cli_cmd_relog, NULL,
cli_cmd_flag_none,
"= re-open log-file (allow rolling logs)" },
- { "note", wpa_cli_cmd_note,
+ { "note", wpa_cli_cmd_note, NULL,
cli_cmd_flag_none,
"<text> = add a note to wpa_supplicant debug log" },
- { "mib", wpa_cli_cmd_mib,
+ { "mib", wpa_cli_cmd_mib, NULL,
cli_cmd_flag_none,
"= get MIB variables (dot1x, dot11)" },
- { "help", wpa_cli_cmd_help,
+ { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
cli_cmd_flag_none,
- "= show this usage help" },
- { "interface", wpa_cli_cmd_interface,
+ "[command] = show usage help" },
+ { "interface", wpa_cli_cmd_interface, NULL,
cli_cmd_flag_none,
"[ifname] = show interfaces/select interface" },
- { "level", wpa_cli_cmd_level,
+ { "level", wpa_cli_cmd_level, NULL,
cli_cmd_flag_none,
"<debug level> = change debug level" },
- { "license", wpa_cli_cmd_license,
+ { "license", wpa_cli_cmd_license, NULL,
cli_cmd_flag_none,
"= show full wpa_cli license" },
- { "quit", wpa_cli_cmd_quit,
+ { "quit", wpa_cli_cmd_quit, NULL,
cli_cmd_flag_none,
"= exit wpa_cli" },
- { "set", wpa_cli_cmd_set,
+ { "set", wpa_cli_cmd_set, wpa_cli_complete_set,
cli_cmd_flag_none,
"= set variables (shows list of variables when run without "
"arguments)" },
- { "get", wpa_cli_cmd_get,
+ { "get", wpa_cli_cmd_get, NULL,
cli_cmd_flag_none,
"<name> = get information" },
- { "logon", wpa_cli_cmd_logon,
+ { "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
- { "logoff", wpa_cli_cmd_logoff,
+ { "logoff", wpa_cli_cmd_logoff, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logoff" },
- { "pmksa", wpa_cli_cmd_pmksa,
+ { "pmksa", wpa_cli_cmd_pmksa, NULL,
cli_cmd_flag_none,
"= show PMKSA cache" },
- { "reassociate", wpa_cli_cmd_reassociate,
+ { "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
- { "preauthenticate", wpa_cli_cmd_preauthenticate,
+ { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
- { "identity", wpa_cli_cmd_identity,
+ { "identity", wpa_cli_cmd_identity, NULL,
cli_cmd_flag_none,
"<network id> <identity> = configure identity for an SSID" },
- { "password", wpa_cli_cmd_password,
+ { "password", wpa_cli_cmd_password, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = configure password for an SSID" },
- { "new_password", wpa_cli_cmd_new_password,
+ { "new_password", wpa_cli_cmd_new_password, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = change password for an SSID" },
- { "pin", wpa_cli_cmd_pin,
+ { "pin", wpa_cli_cmd_pin, NULL,
cli_cmd_flag_sensitive,
"<network id> <pin> = configure pin for an SSID" },
- { "otp", wpa_cli_cmd_otp,
+ { "otp", wpa_cli_cmd_otp, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
- { "passphrase", wpa_cli_cmd_passphrase,
+ { "passphrase", wpa_cli_cmd_passphrase, NULL,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
- { "bssid", wpa_cli_cmd_bssid,
+ { "sim", wpa_cli_cmd_sim, NULL,
+ cli_cmd_flag_sensitive,
+ "<network id> <pin> = report SIM operation result" },
+ { "bssid", wpa_cli_cmd_bssid, NULL,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
- { "blacklist", wpa_cli_cmd_blacklist,
+ { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = add a BSSID to the blacklist\n"
"blacklist clear = clear the blacklist\n"
"blacklist = display the blacklist" },
- { "log_level", wpa_cli_cmd_log_level,
+ { "log_level", wpa_cli_cmd_log_level, NULL,
cli_cmd_flag_none,
"<level> [<timestamp>] = update the log level/timestamp\n"
"log_level = display the current log level and log options" },
- { "list_networks", wpa_cli_cmd_list_networks,
+ { "list_networks", wpa_cli_cmd_list_networks, NULL,
cli_cmd_flag_none,
"= list configured networks" },
- { "select_network", wpa_cli_cmd_select_network,
+ { "select_network", wpa_cli_cmd_select_network, NULL,
cli_cmd_flag_none,
"<network id> = select a network (disable others)" },
- { "enable_network", wpa_cli_cmd_enable_network,
+ { "enable_network", wpa_cli_cmd_enable_network, NULL,
cli_cmd_flag_none,
"<network id> = enable a network" },
- { "disable_network", wpa_cli_cmd_disable_network,
+ { "disable_network", wpa_cli_cmd_disable_network, NULL,
cli_cmd_flag_none,
"<network id> = disable a network" },
- { "add_network", wpa_cli_cmd_add_network,
+ { "add_network", wpa_cli_cmd_add_network, NULL,
cli_cmd_flag_none,
"= add a network" },
- { "remove_network", wpa_cli_cmd_remove_network,
+ { "remove_network", wpa_cli_cmd_remove_network, NULL,
cli_cmd_flag_none,
"<network id> = remove a network" },
- { "set_network", wpa_cli_cmd_set_network,
+ { "set_network", wpa_cli_cmd_set_network, NULL,
cli_cmd_flag_sensitive,
"<network id> <variable> <value> = set network variables (shows\n"
" list of variables when run without arguments)" },
- { "get_network", wpa_cli_cmd_get_network,
+ { "get_network", wpa_cli_cmd_get_network, NULL,
cli_cmd_flag_none,
"<network id> <variable> = get network variables" },
- { "save_config", wpa_cli_cmd_save_config,
+ { "list_creds", wpa_cli_cmd_list_creds, NULL,
+ cli_cmd_flag_none,
+ "= list configured credentials" },
+ { "add_cred", wpa_cli_cmd_add_cred, NULL,
+ cli_cmd_flag_none,
+ "= add a credential" },
+ { "remove_cred", wpa_cli_cmd_remove_cred, NULL,
+ cli_cmd_flag_none,
+ "<cred id> = remove a credential" },
+ { "set_cred", wpa_cli_cmd_set_cred, NULL,
+ cli_cmd_flag_sensitive,
+ "<cred id> <variable> <value> = set credential variables" },
+ { "save_config", wpa_cli_cmd_save_config, NULL,
cli_cmd_flag_none,
"= save the current configuration" },
- { "disconnect", wpa_cli_cmd_disconnect,
+ { "disconnect", wpa_cli_cmd_disconnect, NULL,
cli_cmd_flag_none,
"= disconnect and wait for reassociate/reconnect command before\n"
" connecting" },
- { "reconnect", wpa_cli_cmd_reconnect,
+ { "reconnect", wpa_cli_cmd_reconnect, NULL,
cli_cmd_flag_none,
"= like reassociate, but only takes effect if already disconnected"
},
- { "scan", wpa_cli_cmd_scan,
+ { "scan", wpa_cli_cmd_scan, NULL,
cli_cmd_flag_none,
"= request new BSS scan" },
- { "scan_results", wpa_cli_cmd_scan_results,
+ { "scan_results", wpa_cli_cmd_scan_results, NULL,
cli_cmd_flag_none,
"= get latest scan results" },
- { "bss", wpa_cli_cmd_bss,
+ { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
- { "get_capability", wpa_cli_cmd_get_capability,
+ { "get_capability", wpa_cli_cmd_get_capability, NULL,
cli_cmd_flag_none,
- "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
- { "reconfigure", wpa_cli_cmd_reconfigure,
+ "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
+ "= get capabilies" },
+ { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
cli_cmd_flag_none,
"= force wpa_supplicant to re-read its configuration file" },
- { "terminate", wpa_cli_cmd_terminate,
+ { "terminate", wpa_cli_cmd_terminate, NULL,
cli_cmd_flag_none,
"= terminate wpa_supplicant" },
- { "interface_add", wpa_cli_cmd_interface_add,
+ { "interface_add", wpa_cli_cmd_interface_add, NULL,
cli_cmd_flag_none,
"<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
" <bridge_name> = adds new interface, all parameters but <ifname>\n"
" are optional" },
- { "interface_remove", wpa_cli_cmd_interface_remove,
+ { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
cli_cmd_flag_none,
"<ifname> = removes the interface" },
- { "interface_list", wpa_cli_cmd_interface_list,
+ { "interface_list", wpa_cli_cmd_interface_list, NULL,
cli_cmd_flag_none,
"= list available interfaces" },
- { "ap_scan", wpa_cli_cmd_ap_scan,
+ { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
cli_cmd_flag_none,
"<value> = set ap_scan parameter" },
- { "scan_interval", wpa_cli_cmd_scan_interval,
+ { "scan_interval", wpa_cli_cmd_scan_interval, NULL,
cli_cmd_flag_none,
"<value> = set scan_interval parameter (in seconds)" },
- { "bss_expire_age", wpa_cli_cmd_bss_expire_age,
+ { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
cli_cmd_flag_none,
"<value> = set BSS expiration age parameter" },
- { "bss_expire_count", wpa_cli_cmd_bss_expire_count,
+ { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
cli_cmd_flag_none,
"<value> = set BSS expiration scan count parameter" },
- { "stkstart", wpa_cli_cmd_stkstart,
+ { "bss_flush", wpa_cli_cmd_bss_flush, NULL,
+ cli_cmd_flag_none,
+ "<value> = set BSS flush age (0 by default)" },
+ { "stkstart", wpa_cli_cmd_stkstart, NULL,
cli_cmd_flag_none,
"<addr> = request STK negotiation with <addr>" },
- { "ft_ds", wpa_cli_cmd_ft_ds,
+ { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = request over-the-DS FT with <addr>" },
- { "wps_pbc", wpa_cli_cmd_wps_pbc,
+ { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
- { "wps_pin", wpa_cli_cmd_wps_pin,
+ { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
"<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
"hardcoded)" },
- { "wps_check_pin", wpa_cli_cmd_wps_check_pin,
+ { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
cli_cmd_flag_sensitive,
"<PIN> = verify PIN checksum" },
- { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
+ { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
"Cancels the pending WPS operation" },
-#ifdef CONFIG_WPS_OOB
- { "wps_oob", wpa_cli_cmd_wps_oob,
+#ifdef CONFIG_WPS_NFC
+ { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "[BSSID] = start Wi-Fi Protected Setup: NFC" },
+ { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
+ cli_cmd_flag_none,
+ "<WPS|NDEF> = build configuration token" },
+ { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
+ cli_cmd_flag_none,
+ "<WPS|NDEF> = create password token" },
+ { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
cli_cmd_flag_sensitive,
- "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
-#endif /* CONFIG_WPS_OOB */
- { "wps_reg", wpa_cli_cmd_wps_reg,
+ "<hexdump of payload> = report read NFC tag with WPS data" },
+ { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+ cli_cmd_flag_none,
+ "<NDEF> <WPS> = create NFC handover request" },
+ { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+ cli_cmd_flag_none,
+ "<NDEF> <WPS> = create NFC handover select" },
+ { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+ cli_cmd_flag_none,
+ "<hexdump of payload> = report received NFC handover request" },
+ { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+ cli_cmd_flag_none,
+ "<hexdump of payload> = report received NFC handover select" },
+ { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
+ cli_cmd_flag_none,
+ "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
+ "NFC handover" },
+#endif /* CONFIG_WPS_NFC */
+ { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
- { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
+ { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
cli_cmd_flag_sensitive,
"[params..] = enable/disable AP PIN" },
- { "wps_er_start", wpa_cli_cmd_wps_er_start,
+ { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
cli_cmd_flag_none,
"[IP address] = start Wi-Fi Protected Setup External Registrar" },
- { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
+ { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
cli_cmd_flag_none,
"= stop Wi-Fi Protected Setup External Registrar" },
- { "wps_er_pin", wpa_cli_cmd_wps_er_pin,
+ { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
- { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
+ { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
cli_cmd_flag_none,
"<UUID> = accept an Enrollee PBC using External Registrar" },
- { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
+ { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = learn AP configuration" },
- { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config,
+ { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
cli_cmd_flag_none,
"<UUID> <network id> = set AP configuration for enrolling" },
- { "wps_er_config", wpa_cli_cmd_wps_er_config,
+ { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
- { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
+#ifdef CONFIG_WPS_NFC
+ { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
+ cli_cmd_flag_none,
+ "<WPS/NDEF> <UUID> = build NFC configuration token" },
+#endif /* CONFIG_WPS_NFC */
+ { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
#ifdef CONFIG_AP
- { "sta", wpa_cli_cmd_sta,
+ { "sta", wpa_cli_cmd_sta, NULL,
cli_cmd_flag_none,
"<addr> = get information about an associated station (AP)" },
- { "all_sta", wpa_cli_cmd_all_sta,
+ { "all_sta", wpa_cli_cmd_all_sta, NULL,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
+ { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
+ cli_cmd_flag_none,
+ "<addr> = deauthenticate a station" },
+ { "disassociate", wpa_cli_cmd_disassociate, NULL,
+ cli_cmd_flag_none,
+ "<addr> = disassociate a station" },
+ { "chan_switch", wpa_cli_cmd_chanswitch, NULL,
+ cli_cmd_flag_none,
+ "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
+ " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
+ " = CSA parameters" },
#endif /* CONFIG_AP */
- { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
+ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
- { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
+ { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
"= notification of resume/thaw" },
- { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
+ { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
"= drop SA without deauth/disassoc (test command)" },
- { "roam", wpa_cli_cmd_roam,
+ { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
#ifdef CONFIG_P2P
- { "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
+ { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
+ cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
- { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, cli_cmd_flag_none,
+ { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
"= stop P2P Devices search" },
- { "p2p_connect", wpa_cli_cmd_p2p_connect, cli_cmd_flag_none,
- "<addr> <\"pbc\"|PIN> = connect to a P2P Devices" },
- { "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none,
+ { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
+ cli_cmd_flag_none,
+ "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
+ { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
"[timeout] = listen for P2P Devices for up-to timeout seconds" },
- { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none,
+ { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
+ wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
"<ifname> = remove P2P group interface (terminate group if GO)" },
- { "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none,
- "= add a new P2P group (local end as GO)" },
- { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
+ { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
+ "[ht40] = add a new P2P group (local end as GO)" },
+ { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
- { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,
+ { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
cli_cmd_flag_none,
"= get the passphrase for a group (GO only)" },
{ "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
- cli_cmd_flag_none,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <TLVs> = schedule service discovery request" },
{ "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
- cli_cmd_flag_none,
+ NULL, cli_cmd_flag_none,
"<id> = cancel pending service discovery request" },
- { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
+ { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
cli_cmd_flag_none,
"<freq> <addr> <dialog token> <TLVs> = service discovery response" },
- { "p2p_service_update", wpa_cli_cmd_p2p_service_update,
+ { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
cli_cmd_flag_none,
"= indicate change in local services" },
- { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external,
+ { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
cli_cmd_flag_none,
"<external> = set external processing of service discovery" },
- { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush,
+ { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
cli_cmd_flag_none,
"= remove all stored service entries" },
- { "p2p_service_add", wpa_cli_cmd_p2p_service_add,
+ { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> <response|service> = add a local "
"service" },
- { "p2p_service_del", wpa_cli_cmd_p2p_service_del,
+ { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> [|service] = remove a local "
"service" },
- { "p2p_reject", wpa_cli_cmd_p2p_reject,
+ { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
cli_cmd_flag_none,
"<addr> = reject connection attempts from a specific peer" },
- { "p2p_invite", wpa_cli_cmd_p2p_invite,
+ { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
cli_cmd_flag_none,
"<cmd> [peer=addr] = invite peer" },
- { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
+ { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
"[discovered] = list known (optionally, only fully discovered) P2P "
"peers" },
- { "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none,
+ { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
+ cli_cmd_flag_none,
"<address> = show information about known P2P peer" },
- { "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none,
+ { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set,
+ cli_cmd_flag_none,
"<field> <value> = set a P2P parameter" },
- { "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none,
+ { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
"= flush P2P state" },
- { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
+ { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
"= cancel P2P group formation" },
- { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
+ { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<address> = unauthorize a peer" },
- { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none,
+ { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
+ cli_cmd_flag_none,
"[<duration> <interval>] [<duration> <interval>] = request GO "
"presence" },
- { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
+ { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
+ cli_cmd_flag_none,
"[<period> <interval>] = set extended listen timing" },
+ { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
+ "<address|iface=address> = remove a peer from all groups" },
#endif /* CONFIG_P2P */
-
+#ifdef CONFIG_WIFI_DISPLAY
+ { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
+ cli_cmd_flag_none,
+ "<subelem> [contents] = set Wi-Fi Display subelement" },
+ { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
+ cli_cmd_flag_none,
+ "<subelem> = get Wi-Fi Display subelement" },
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
- { "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
+ { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
"= fetch ANQP information for all APs" },
- { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
+ { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
+ cli_cmd_flag_none,
"= stop fetch_anqp operation" },
- { "interworking_select", wpa_cli_cmd_interworking_select,
+ { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
cli_cmd_flag_none,
"[auto] = perform Interworking network selection" },
{ "interworking_connect", wpa_cli_cmd_interworking_connect,
- cli_cmd_flag_none,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
- { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+ { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
+ { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "<addr> <AdvProtoID> [QueryReq] = GAS request" },
+ { "gas_response_get", wpa_cli_cmd_gas_response_get,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
+ "<addr> <dialog token> [start,len] = Fetch last GAS response" },
#endif /* CONFIG_INTERWORKING */
- { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
+#ifdef CONFIG_HS20
+ { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
+ },
+ { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
+ "<addr> <home realm> = get HS20 nai home realm list" },
+#endif /* CONFIG_HS20 */
+ { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
+ cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
- { "tdls_discover", wpa_cli_cmd_tdls_discover,
+ { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
cli_cmd_flag_none,
"<addr> = request TDLS discovery with <addr>" },
- { "tdls_setup", wpa_cli_cmd_tdls_setup,
+ { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
cli_cmd_flag_none,
"<addr> = request TDLS setup with <addr>" },
- { "tdls_teardown", wpa_cli_cmd_tdls_teardown,
+ { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
- { "signal_poll", wpa_cli_cmd_signal_poll,
+ { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
- { NULL, NULL, cli_cmd_flag_none, NULL }
+ { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
+ cli_cmd_flag_none,
+ "= get TX/RX packet counters" },
+ { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
+ cli_cmd_flag_none,
+ "= trigger IEEE 802.1X/EAPOL reauthentication" },
+#ifdef CONFIG_AUTOSCAN
+ { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
+ "[params] = Set or unset (if none) autoscan parameters" },
+#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_WNM
+ { "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" },
+#endif /* CONFIG_WNM */
+ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
+ "<params..> = Sent unprocessed command" },
+ { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
+ "= flush wpa_supplicant state" },
+#ifdef ANDROID
+ { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none,
+ "<command> = driver private commands" },
+#endif /* ANDROID */
+ { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none,
+ "= radio_work <show/add/done>" },
+ { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3034,12 +2924,14 @@ static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
}
-static void print_help(void)
+static void print_help(const char *cmd)
{
int n;
printf("commands:\n");
- for (n = 0; wpa_cli_commands[n].cmd; n++)
- print_cmd_help(&wpa_cli_commands[n], " ");
+ for (n = 0; wpa_cli_commands[n].cmd; n++) {
+ if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
+ print_cmd_help(&wpa_cli_commands[n], " ");
+ }
}
@@ -3068,9 +2960,12 @@ static char ** wpa_list_cmd_list(void)
{
char **res;
int i, count;
+ struct cli_txt_entry *e;
- count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
- res = os_zalloc(count * sizeof(char *));
+ count = ARRAY_SIZE(wpa_cli_commands);
+ count += dl_list_len(&p2p_groups);
+ count += dl_list_len(&ifnames);
+ res = os_calloc(count + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -3080,6 +2975,22 @@ static char ** wpa_list_cmd_list(void)
break;
}
+ dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
+ size_t len = 8 + os_strlen(e->txt);
+ res[i] = os_malloc(len);
+ if (res[i] == NULL)
+ break;
+ os_snprintf(res[i], len, "ifname=%s", e->txt);
+ i++;
+ }
+
+ dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
+ res[i] = os_strdup(e->txt);
+ if (res[i] == NULL)
+ break;
+ i++;
+ }
+
return res;
}
@@ -3089,19 +3000,11 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
{
int i;
- if (os_strcasecmp(cmd, "bss") == 0)
- return wpa_cli_complete_bss(str, pos);
-#ifdef CONFIG_P2P
- if (os_strcasecmp(cmd, "p2p_connect") == 0)
- return wpa_cli_complete_p2p_connect(str, pos);
- if (os_strcasecmp(cmd, "p2p_peer") == 0)
- return wpa_cli_complete_p2p_peer(str, pos);
- if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
- return wpa_cli_complete_p2p_group_remove(str, pos);
-#endif /* CONFIG_P2P */
-
for (i = 0; wpa_cli_commands[i].cmd; i++) {
if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
+ if (wpa_cli_commands[i].completion)
+ return wpa_cli_commands[i].completion(str,
+ pos);
edit_clear_line();
printf("\r%s\n", wpa_cli_commands[i].usage);
edit_redraw();
@@ -3119,6 +3022,14 @@ static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
const char *end;
char *cmd;
+ if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
+ end = os_strchr(str, ' ');
+ if (end && pos > end - str) {
+ pos -= end - str + 1;
+ str = end + 1;
+ }
+ }
+
end = os_strchr(str, ' ');
if (end == NULL || str + pos < end)
return wpa_list_cmd_list();
@@ -3140,6 +3051,16 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
int count;
int ret = 0;
+ if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
+ ifname_prefix = argv[0] + 7;
+ argv = &argv[1];
+ argc--;
+ } else
+ ifname_prefix = NULL;
+
+ if (argc == 0)
+ return -1;
+
count = 0;
cmd = wpa_cli_commands;
while (cmd->cmd) {
@@ -3259,7 +3180,7 @@ static void wpa_cli_action_process(const char *msg)
os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
- if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
+ if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) {
wpa_cli_connected = 1;
wpa_cli_last_id = new_id;
wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
@@ -3277,10 +3198,18 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPS_EVENT_FAIL)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, AP_STA_CONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -3299,7 +3228,14 @@ static void wpa_cli_action_cb(char *msg, size_t len)
static void wpa_cli_reconnect(void)
{
wpa_cli_close_connection();
- wpa_cli_open_connection(ctrl_ifname, 1);
+ if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+ return;
+
+ if (interactive) {
+ edit_clear_line();
+ printf("\rConnection to wpa_supplicant re-established\n");
+ edit_redraw();
+ }
}
@@ -3371,6 +3307,33 @@ static void cli_event(const char *str)
}
+static int check_terminating(const char *msg)
+{
+ const char *pos = msg;
+
+ if (*pos == '<') {
+ /* skip priority */
+ pos = os_strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+ edit_clear_line();
+ printf("\rConnection to wpa_supplicant lost - trying to "
+ "reconnect\n");
+ edit_redraw();
+ wpa_cli_attached = 0;
+ wpa_cli_close_connection();
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
{
if (ctrl_conn == NULL) {
@@ -3391,6 +3354,9 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
printf("\r%s\n", buf);
edit_redraw();
}
+
+ if (interactive && check_terminating(buf) > 0)
+ return;
}
} else {
printf("Could not read pending message.\n");
@@ -3450,12 +3416,6 @@ static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
}
-static void wpa_cli_eloop_terminate(int sig, void *signal_ctx)
-{
- eloop_terminate();
-}
-
-
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
wpa_cli_recv_pending(mon_conn, 0);
@@ -3478,11 +3438,18 @@ static void wpa_cli_edit_eof_cb(void *ctx)
}
-static void wpa_cli_interactive(void)
+static int warning_displayed = 0;
+static char *hfile = NULL;
+static int edit_started = 0;
+
+static void start_edit(void)
{
- char *home, *hfile = NULL;
+ char *home;
+ char *ps = NULL;
- printf("\nInteractive mode\n\n");
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
home = getenv("HOME");
if (home) {
@@ -3493,17 +3460,122 @@ static void wpa_cli_interactive(void)
os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
}
- eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL);
- edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
- wpa_cli_edit_completion_cb, NULL, hfile);
+ if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
+ wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
+ eloop_terminate();
+ return;
+ }
+
+ edit_started = 1;
eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+}
+
+
+static void update_bssid_list(struct wpa_ctrl *ctrl)
+{
+ char buf[4096];
+ size_t len = sizeof(buf);
+ int ret;
+ char *cmd = "BSS RANGE=ALL MASK=0x2";
+ char *pos, *end;
+
+ if (ctrl == NULL)
+ return;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+ if (ret < 0)
+ return;
+ buf[len] = '\0';
+
+ pos = buf;
+ while (pos) {
+ pos = os_strstr(pos, "bssid=");
+ if (pos == NULL)
+ break;
+ pos += 6;
+ end = os_strchr(pos, '\n');
+ if (end == NULL)
+ break;
+ *end = '\0';
+ cli_txt_list_add(&bsses, pos);
+ pos = end + 1;
+ }
+}
+
+
+static void update_ifnames(struct wpa_ctrl *ctrl)
+{
+ char buf[4096];
+ size_t len = sizeof(buf);
+ int ret;
+ char *cmd = "INTERFACES";
+ char *pos, *end;
+ char txt[200];
+
+ cli_txt_list_flush(&ifnames);
+
+ if (ctrl == NULL)
+ return;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+ if (ret < 0)
+ return;
+ buf[len] = '\0';
+
+ pos = buf;
+ while (pos) {
+ end = os_strchr(pos, '\n');
+ if (end == NULL)
+ break;
+ *end = '\0';
+ ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
+ if (ret > 0 && ret < (int) sizeof(txt))
+ cli_txt_list_add(&ifnames, txt);
+ pos = end + 1;
+ }
+}
+
+
+static void try_connection(void *eloop_ctx, void *timeout_ctx)
+{
+ if (ctrl_conn)
+ goto done;
+
+ if (ctrl_ifname == NULL)
+ ctrl_ifname = wpa_cli_get_default_ifname();
+
+ if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+ if (!warning_displayed) {
+ printf("Could not connect to wpa_supplicant: "
+ "%s - re-trying\n", ctrl_ifname);
+ warning_displayed = 1;
+ }
+ eloop_register_timeout(1, 0, try_connection, NULL, NULL);
+ return;
+ }
+ update_bssid_list(ctrl_conn);
+
+ if (warning_displayed)
+ printf("Connection established.\n");
+
+done:
+ start_edit();
+}
+
+
+static void wpa_cli_interactive(void)
+{
+ printf("\nInteractive mode\n\n");
+
+ eloop_register_timeout(0, 0, try_connection, NULL, NULL);
eloop_run();
+ eloop_cancel_timeout(try_connection, NULL, NULL);
cli_txt_list_flush(&p2p_peers);
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
- edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
+ cli_txt_list_flush(&ifnames);
+ if (edit_started)
+ edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
os_free(hfile);
eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
wpa_cli_close_connection();
@@ -3562,10 +3634,10 @@ static void wpa_cli_cleanup(void)
os_program_deinit();
}
-static void wpa_cli_terminate(int sig)
+
+static void wpa_cli_terminate(int sig, void *ctx)
{
- wpa_cli_cleanup();
- exit(0);
+ eloop_terminate();
}
@@ -3608,7 +3680,7 @@ static char * wpa_cli_get_default_ifname(void)
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- char buf[2048], *pos;
+ char buf[4096], *pos;
size_t len;
struct wpa_ctrl *ctrl;
int ret;
@@ -3635,7 +3707,6 @@ static char * wpa_cli_get_default_ifname(void)
int main(int argc, char *argv[])
{
- int warning_displayed = 0;
int c;
int daemonize = 0;
int ret = 0;
@@ -3698,41 +3769,44 @@ int main(int argc, char *argv[])
ctrl_conn = wpa_ctrl_open(global);
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
if (ctrl_conn == NULL) {
- perror("Failed to connect to wpa_supplicant - "
- "wpa_ctrl_open");
+ fprintf(stderr, "Failed to connect to wpa_supplicant "
+ "global interface: %s error: %s\n",
+ global, strerror(errno));
return -1;
}
+
+ if (interactive) {
+ update_ifnames(ctrl_conn);
+ mon_conn = wpa_ctrl_open(global);
+ if (mon_conn) {
+ if (wpa_ctrl_attach(mon_conn) == 0) {
+ wpa_cli_attached = 1;
+ eloop_register_read_sock(
+ wpa_ctrl_get_fd(mon_conn),
+ wpa_cli_mon_receive,
+ NULL, NULL);
+ } else {
+ printf("Failed to open monitor "
+ "connection through global "
+ "control interface\n");
+ }
+ }
+ }
}
-#ifndef _WIN32_WCE
- signal(SIGINT, wpa_cli_terminate);
- signal(SIGTERM, wpa_cli_terminate);
-#endif /* _WIN32_WCE */
+ eloop_register_signal_terminate(wpa_cli_terminate, NULL);
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
if (interactive) {
- for (; !global;) {
- if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
- if (warning_displayed)
- printf("Connection established.\n");
- break;
- }
-
- if (!warning_displayed) {
- printf("Could not connect to wpa_supplicant - "
- "re-trying\n");
- warning_displayed = 1;
- }
- os_sleep(1, 0);
- continue;
- }
+ wpa_cli_interactive();
} else {
if (!global &&
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
- perror("Failed to connect to wpa_supplicant - "
- "wpa_ctrl_open");
+ fprintf(stderr, "Failed to connect to non-global "
+ "ctrl_ifname: %s error: %s\n",
+ ctrl_ifname, strerror(errno));
return -1;
}
@@ -3745,17 +3819,16 @@ int main(int argc, char *argv[])
return -1;
}
}
- }
- if (daemonize && os_daemonize(pid_file))
- return -1;
+ if (daemonize && os_daemonize(pid_file))
+ return -1;
- if (interactive)
- wpa_cli_interactive();
- else if (action_file)
- wpa_cli_action(ctrl_conn);
- else
- ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+ if (action_file)
+ wpa_cli_action(ctrl_conn);
+ else
+ ret = wpa_request(ctrl_conn, argc - optind,
+ &argv[optind]);
+ }
os_free(ctrl_ifname);
eloop_destroy();
diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.cpp b/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
index 88d4603..27cbdd6 100644
--- a/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
@@ -2,14 +2,8 @@
* wpa_gui - AddInterface class
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include <cstdio>
diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.h b/wpa_supplicant/wpa_gui-qt4/addinterface.h
index 9d9476a..1b4c98d 100644
--- a/wpa_supplicant/wpa_gui-qt4/addinterface.h
+++ b/wpa_supplicant/wpa_gui-qt4/addinterface.h
@@ -2,14 +2,8 @@
* wpa_gui - AddInterface class
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef ADDINTERFACE_H
diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
index 1eb0b7b..a36085d 100644
--- a/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
@@ -2,14 +2,8 @@
* wpa_gui - EventHistory class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include <QHeaderView>
diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/wpa_supplicant/wpa_gui-qt4/eventhistory.h
index 40dff6d..3c01aa8 100644
--- a/wpa_supplicant/wpa_gui-qt4/eventhistory.h
+++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.h
@@ -2,14 +2,8 @@
* wpa_gui - EventHistory class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef EVENTHISTORY_H
diff --git a/wpa_supplicant/wpa_gui-qt4/main.cpp b/wpa_supplicant/wpa_gui-qt4/main.cpp
index 6170b15..73d677c 100644
--- a/wpa_supplicant/wpa_gui-qt4/main.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/main.cpp
@@ -2,14 +2,8 @@
* wpa_gui - Application startup
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifdef CONFIG_NATIVE_WINDOWS
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
index fe50a8d..737c41c 100644
--- a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
@@ -2,14 +2,8 @@
* wpa_gui - NetworkConfig class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include <cstdio>
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/wpa_supplicant/wpa_gui-qt4/networkconfig.h
index 0ceeb41..429b648 100644
--- a/wpa_supplicant/wpa_gui-qt4/networkconfig.h
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.h
@@ -2,14 +2,8 @@
* wpa_gui - NetworkConfig class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef NETWORKCONFIG_H
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 65bb17d..f5aa9f7 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp
@@ -2,14 +2,8 @@
* wpa_gui - Peers class
* Copyright (c) 2009-2010, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include <cstdio>
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.h b/wpa_supplicant/wpa_gui-qt4/peers.h
index a715395..bac77dc 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.h
+++ b/wpa_supplicant/wpa_gui-qt4/peers.h
@@ -2,14 +2,8 @@
* wpa_gui - Peers class
* Copyright (c) 2009-2010, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef PEERS_H
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
index 459aa8c..063347e 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -2,19 +2,14 @@
* wpa_gui - ScanResults class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include <cstdio>
#include "scanresults.h"
+#include "signalbar.h"
#include "wpagui.h"
#include "networkconfig.h"
@@ -33,6 +28,7 @@ ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags)
wpagui = NULL;
scanResultsWidget->setItemsExpandable(FALSE);
scanResultsWidget->setRootIsDecorated(FALSE);
+ scanResultsWidget->setItemDelegate(new SignalBar(scanResultsWidget));
}
@@ -91,7 +87,7 @@ void ScanResults::updateResults()
bssid = (*it).mid(pos);
else if ((*it).startsWith("freq="))
freq = (*it).mid(pos);
- else if ((*it).startsWith("qual="))
+ else if ((*it).startsWith("level="))
signal = (*it).mid(pos);
else if ((*it).startsWith("flags="))
flags = (*it).mid(pos);
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.h b/wpa_supplicant/wpa_gui-qt4/scanresults.h
index 2c4a1b0..4a5842c 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.h
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.h
@@ -2,14 +2,8 @@
* wpa_gui - ScanResults class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef SCANRESULTS_H
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.cpp b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
new file mode 100644
index 0000000..2bba582
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
@@ -0,0 +1,58 @@
+/*
+ * wpa_gui - SignalBar class
+ * Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <cstdio>
+#include <qapplication.h>
+
+#include "signalbar.h"
+
+
+SignalBar::SignalBar(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+
+
+SignalBar::~SignalBar()
+{
+}
+
+
+void SignalBar::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QStyleOptionProgressBar opts;
+ int signal;
+
+ if (index.column() != 3) {
+ QStyledItemDelegate::paint(painter, option, index);
+ return;
+ }
+
+ if (index.data().toInt() > 0)
+ signal = 0 - (256 - index.data().toInt());
+ else
+ signal = index.data().toInt();
+
+ opts.minimum = -95;
+ opts.maximum = -35;
+ if (signal < opts.minimum)
+ opts.progress = opts.minimum;
+ else if (signal > opts.maximum)
+ opts.progress = opts.maximum;
+ else
+ opts.progress = signal;
+
+ opts.text = QString::number(signal) + " dBm";
+ opts.textVisible = true;
+ opts.rect = option.rect;
+
+ QApplication::style()->drawControl(QStyle::CE_ProgressBar,
+ &opts, painter);
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.h b/wpa_supplicant/wpa_gui-qt4/signalbar.h
new file mode 100644
index 0000000..37da5dd
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/signalbar.h
@@ -0,0 +1,28 @@
+/*
+ * wpa_gui - SignalBar class
+ * Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SIGNALBAR_H
+#define SIGNALBAR_H
+
+#include <QObject>
+#include <QStyledItemDelegate>
+
+class SignalBar : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ SignalBar(QObject *parent = 0);
+ ~SignalBar();
+
+ virtual void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const ;
+};
+
+#endif /* SIGNALBAR_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/stringquery.cpp b/wpa_supplicant/wpa_gui-qt4/stringquery.cpp
index 1ca98d9..420e0be 100644
--- a/wpa_supplicant/wpa_gui-qt4/stringquery.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/stringquery.cpp
@@ -2,14 +2,8 @@
* wpa_gui - StringQuery class
* Copyright (c) 2009, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include <cstdio>
diff --git a/wpa_supplicant/wpa_gui-qt4/stringquery.h b/wpa_supplicant/wpa_gui-qt4/stringquery.h
index 1b68217..9d6bffd 100644
--- a/wpa_supplicant/wpa_gui-qt4/stringquery.h
+++ b/wpa_supplicant/wpa_gui-qt4/stringquery.h
@@ -2,14 +2,8 @@
* wpa_gui - StringQuery class
* Copyright (c) 2009, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef STRINGQUERY_H
diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
index 345f965..ba4c9f4 100644
--- a/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
@@ -2,14 +2,8 @@
* wpa_gui - UserDataRequest class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "userdatarequest.h"
diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
index 2b6e837..0d9dbfc 100644
--- a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
+++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
@@ -2,14 +2,8 @@
* wpa_gui - UserDataRequest class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef USERDATAREQUEST_H
diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
index 85848d7..3c81929 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
+++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -34,6 +34,7 @@ HEADERS += wpamsg.h \
wpagui.h \
eventhistory.h \
scanresults.h \
+ signalbar.h \
userdatarequest.h \
networkconfig.h \
addinterface.h \
@@ -44,6 +45,7 @@ SOURCES += main.cpp \
wpagui.cpp \
eventhistory.cpp \
scanresults.cpp \
+ signalbar.cpp \
userdatarequest.cpp \
networkconfig.cpp \
addinterface.cpp \
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 5ac8994..6bba8d2 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -2,14 +2,8 @@
* wpa_gui - WpaGui class
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifdef CONFIG_NATIVE_WINDOWS
@@ -715,17 +709,13 @@ void WpaGui::helpContents()
void WpaGui::helpAbout()
{
QMessageBox::about(this, "wpa_gui for wpa_supplicant",
- "Copyright (c) 2003-2011,\n"
+ "Copyright (c) 2003-2013,\n"
"Jouni Malinen <j@w1.fi>\n"
"and contributors.\n"
"\n"
- "This program is free software. You can\n"
- "distribute it and/or modify it under the terms "
- "of\n"
- "the GNU General Public License version 2.\n"
- "\n"
- "Alternatively, this software may be distributed\n"
- "under the terms of the BSD license.\n"
+ "This software may be distributed under\n"
+ "the terms of the BSD license.\n"
+ "See README for more details.\n"
"\n"
"This product includes software developed\n"
"by the OpenSSL Project for use in the\n"
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h
index 2e1af8e..340286c 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -2,14 +2,8 @@
* wpa_gui - WpaGui class
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WPAGUI_H
diff --git a/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/wpa_supplicant/wpa_gui-qt4/wpamsg.h
index 4950b21..8f2fcdc 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpamsg.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpamsg.h
@@ -2,14 +2,8 @@
* wpa_gui - WpaMsg class for storing event messages
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WPAMSG_H
diff --git a/wpa_supplicant/wpa_gui/.gitignore b/wpa_supplicant/wpa_gui/.gitignore
deleted file mode 100644
index 4df64a9..0000000
--- a/wpa_supplicant/wpa_gui/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.moc
-.obj
-.ui
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui b/wpa_supplicant/wpa_gui/eventhistory.ui
deleted file mode 100644
index 3735fb7..0000000
--- a/wpa_supplicant/wpa_gui/eventhistory.ui
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>EventHistory</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>EventHistory</cstring>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>533</width>
- <height>285</height>
- </rect>
- </property>
- <property name="caption">
- <string>Event history</string>
- </property>
- <vbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QListView">
- <column>
- <property name="text">
- <string>Timestamp</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Message</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <property name="name">
- <cstring>eventListView</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>7</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="resizePolicy">
- <enum>Manual</enum>
- </property>
- <property name="selectionMode">
- <enum>NoSelection</enum>
- </property>
- <property name="resizeMode">
- <enum>LastColumn</enum>
- </property>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout30</cstring>
- </property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <spacer>
- <property name="name">
- <cstring>spacer3</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton">
- <property name="name">
- <cstring>closeButton</cstring>
- </property>
- <property name="text">
- <string>Close</string>
- </property>
- </widget>
- </hbox>
- </widget>
- </vbox>
-</widget>
-<connections>
- <connection>
- <sender>closeButton</sender>
- <signal>clicked()</signal>
- <receiver>EventHistory</receiver>
- <slot>close()</slot>
- </connection>
-</connections>
-<includes>
- <include location="local" impldecl="in declaration">wpamsg.h</include>
- <include location="local" impldecl="in implementation">eventhistory.ui.h</include>
-</includes>
-<slots>
- <slot>addEvents( WpaMsgList msgs )</slot>
- <slot>addEvent( WpaMsg msg )</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui.h b/wpa_supplicant/wpa_gui/eventhistory.ui.h
deleted file mode 100644
index cb2caab..0000000
--- a/wpa_supplicant/wpa_gui/eventhistory.ui.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-void EventHistory::init()
-{
-}
-
-
-void EventHistory::destroy()
-{
-}
-
-
-void EventHistory::addEvents(WpaMsgList msgs)
-{
- WpaMsgList::iterator it;
- for (it = msgs.begin(); it != msgs.end(); it++) {
- addEvent(*it);
- }
-}
-
-
-void EventHistory::addEvent(WpaMsg msg)
-{
- Q3ListViewItem *item;
- item = new Q3ListViewItem(eventListView,
- msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
- msg.getMsg());
- if (item == NULL)
- return;
- eventListView->setSelected(item, false);
-}
diff --git a/wpa_supplicant/wpa_gui/main.cpp b/wpa_supplicant/wpa_gui/main.cpp
deleted file mode 100644
index a78473a..0000000
--- a/wpa_supplicant/wpa_gui/main.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <qapplication.h>
-#include "wpagui.h"
-
-int main( int argc, char ** argv )
-{
- QApplication a( argc, argv );
- WpaGui w;
- int ret;
-
-#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
- return -1;
- }
-#endif /* CONFIG_NATIVE_WINDOWS */
-
- w.show();
- a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
- ret = a.exec();
-
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
-
- return ret;
-}
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui b/wpa_supplicant/wpa_gui/networkconfig.ui
deleted file mode 100644
index 019ecf7..0000000
--- a/wpa_supplicant/wpa_gui/networkconfig.ui
+++ /dev/null
@@ -1,475 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>NetworkConfig</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>NetworkConfig</cstring>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>380</width>
- <height>430</height>
- </rect>
- </property>
- <property name="caption">
- <string>NetworkConfig</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QPushButton" row="1" column="3">
- <property name="name">
- <cstring>cancelButton</cstring>
- </property>
- <property name="text">
- <string>Cancel</string>
- </property>
- </widget>
- <widget class="QFrame" row="0" column="0" rowspan="1" colspan="4">
- <property name="name">
- <cstring>frame9</cstring>
- </property>
- <property name="frameShape">
- <enum>StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>Raised</enum>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel" row="0" column="0">
- <property name="name">
- <cstring>textLabel0</cstring>
- </property>
- <property name="text">
- <string>SSID</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="0" column="1">
- <property name="name">
- <cstring>ssidEdit</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- <property name="toolTip" stdset="0">
- <string>Network name (Service Set IDentifier)</string>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="0">
- <property name="name">
- <cstring>textLabel1</cstring>
- </property>
- <property name="text">
- <string>Network ID</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="1" column="1">
- <property name="name">
- <cstring>idstrEdit</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- <property name="toolTip" stdset="0">
- <string>Network Identification String</string>
- </property>
- </widget>
- <widget class="QLabel" row="2" column="0">
- <property name="name">
- <cstring>textLabel2</cstring>
- </property>
- <property name="text">
- <string>Authentication</string>
- </property>
- </widget>
- <widget class="QComboBox" row="2" column="1">
- <item>
- <property name="text">
- <string>Plaintext or static WEP</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>IEEE 802.1X</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA-Personal (PSK)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA-Enterprise (EAP)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA2-Personal (PSK)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA2-Enterprise (EAP)</string>
- </property>
- </item>
- <property name="name">
- <cstring>authSelect</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="3" column="0">
- <property name="name">
- <cstring>textLabel3</cstring>
- </property>
- <property name="text">
- <string>Encryption</string>
- </property>
- </widget>
- <widget class="QComboBox" row="3" column="1">
- <item>
- <property name="text">
- <string>None</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WEP</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>TKIP</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>CCMP</string>
- </property>
- </item>
- <property name="name">
- <cstring>encrSelect</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="4" column="0">
- <property name="name">
- <cstring>textLabel4</cstring>
- </property>
- <property name="text">
- <string>PSK</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="4" column="1">
- <property name="name">
- <cstring>pskEdit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="echoMode">
- <enum>Password</enum>
- </property>
- <property name="toolTip" stdset="0">
- <string>WPA/WPA2 pre-shared key or passphrase</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="5" column="0">
- <property name="name">
- <cstring>textLabel5</cstring>
- </property>
- <property name="text">
- <string>EAP method</string>
- </property>
- </widget>
- <widget class="QComboBox" row="5" column="1">
- <property name="name">
- <cstring>eapSelect</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLabel" row="6" column="0">
- <property name="name">
- <cstring>textLabel6</cstring>
- </property>
- <property name="text">
- <string>Identity</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="6" column="1">
- <property name="name">
- <cstring>identityEdit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="toolTip" stdset="0">
- <string>Username/Identity for EAP methods</string>
- </property>
- </widget>
- <widget class="QLabel" row="7" column="0">
- <property name="name">
- <cstring>textLabel7</cstring>
- </property>
- <property name="text">
- <string>Password</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="7" column="1">
- <property name="name">
- <cstring>passwordEdit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="echoMode">
- <enum>Password</enum>
- </property>
- <property name="toolTip" stdset="0">
- <string>Password for EAP methods</string>
- </property>
- </widget>
- <widget class="QLabel" row="8" column="0">
- <property name="name">
- <cstring>textLabel1_2</cstring>
- </property>
- <property name="text">
- <string>CA certificate</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="8" column="1">
- <property name="name">
- <cstring>cacertEdit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QButtonGroup" row="9" column="0" rowspan="1" colspan="2">
- <property name="name">
- <cstring>buttonGroup1</cstring>
- </property>
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="title">
- <string>WEP keys</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QRadioButton" row="0" column="0">
- <property name="name">
- <cstring>wep0Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 0</string>
- </property>
- </widget>
- <widget class="QRadioButton" row="1" column="0">
- <property name="name">
- <cstring>wep1Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 1</string>
- </property>
- </widget>
- <widget class="QRadioButton" row="3" column="0">
- <property name="name">
- <cstring>wep3Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 3</string>
- </property>
- </widget>
- <widget class="QRadioButton" row="2" column="0">
- <property name="name">
- <cstring>wep2Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 2</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="0" column="1">
- <property name="name">
- <cstring>wep0Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLineEdit" row="1" column="1">
- <property name="name">
- <cstring>wep1Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLineEdit" row="2" column="1">
- <property name="name">
- <cstring>wep2Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLineEdit" row="3" column="1">
- <property name="name">
- <cstring>wep3Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </grid>
- </widget>
- </grid>
- </widget>
- <spacer row="1" column="0">
- <property name="name">
- <cstring>spacer5</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>130</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton" row="1" column="1">
- <property name="name">
- <cstring>addButton</cstring>
- </property>
- <property name="text">
- <string>Add</string>
- </property>
- </widget>
- <widget class="QPushButton" row="1" column="2">
- <property name="name">
- <cstring>removeButton</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Remove</string>
- </property>
- </widget>
- </grid>
-</widget>
-<connections>
- <connection>
- <sender>authSelect</sender>
- <signal>activated(int)</signal>
- <receiver>NetworkConfig</receiver>
- <slot>authChanged(int)</slot>
- </connection>
- <connection>
- <sender>cancelButton</sender>
- <signal>clicked()</signal>
- <receiver>NetworkConfig</receiver>
- <slot>close()</slot>
- </connection>
- <connection>
- <sender>addButton</sender>
- <signal>clicked()</signal>
- <receiver>NetworkConfig</receiver>
- <slot>addNetwork()</slot>
- </connection>
- <connection>
- <sender>encrSelect</sender>
- <signal>activated(const QString&amp;)</signal>
- <receiver>NetworkConfig</receiver>
- <slot>encrChanged(const QString&amp;)</slot>
- </connection>
- <connection>
- <sender>removeButton</sender>
- <signal>clicked()</signal>
- <receiver>NetworkConfig</receiver>
- <slot>removeNetwork()</slot>
- </connection>
-</connections>
-<tabstops>
- <tabstop>ssidEdit</tabstop>
- <tabstop>idstrEdit</tabstop>
- <tabstop>authSelect</tabstop>
- <tabstop>encrSelect</tabstop>
- <tabstop>pskEdit</tabstop>
- <tabstop>eapSelect</tabstop>
- <tabstop>identityEdit</tabstop>
- <tabstop>passwordEdit</tabstop>
- <tabstop>cacertEdit</tabstop>
- <tabstop>wep0Radio</tabstop>
- <tabstop>wep1Radio</tabstop>
- <tabstop>wep2Radio</tabstop>
- <tabstop>wep3Radio</tabstop>
- <tabstop>wep0Edit</tabstop>
- <tabstop>wep1Edit</tabstop>
- <tabstop>wep2Edit</tabstop>
- <tabstop>wep3Edit</tabstop>
- <tabstop>addButton</tabstop>
- <tabstop>removeButton</tabstop>
- <tabstop>cancelButton</tabstop>
-</tabstops>
-<includes>
- <include location="global" impldecl="in declaration">qlistview.h</include>
- <include location="global" impldecl="in implementation">qmessagebox.h</include>
- <include location="local" impldecl="in implementation">wpagui.h</include>
- <include location="local" impldecl="in implementation">networkconfig.ui.h</include>
-</includes>
-<forwards>
- <forward>class WpaGui;</forward>
-</forwards>
-<variables>
- <variable access="private">WpaGui *wpagui;</variable>
- <variable access="private">int edit_network_id;</variable>
- <variable access="private">bool new_network;</variable>
-</variables>
-<slots>
- <slot>authChanged( int sel )</slot>
- <slot>addNetwork()</slot>
- <slot>encrChanged( const QString &amp; sel )</slot>
- <slot>writeWepKey( int network_id, QLineEdit * edit, int id )</slot>
- <slot>removeNetwork()</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function>paramsFromScanResults( QListViewItem * sel )</function>
- <function>setWpaGui( WpaGui * _wpagui )</function>
- <function returnType="int">setNetworkParam( int id, const char * field, const char * value, bool quote )</function>
- <function access="private">wepEnabled( bool enabled )</function>
- <function>paramsFromConfig( int network_id )</function>
- <function>newNetwork()</function>
- <function access="private">getEapCapa()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui.h b/wpa_supplicant/wpa_gui/networkconfig.ui.h
deleted file mode 100644
index 501d5d2..0000000
--- a/wpa_supplicant/wpa_gui/networkconfig.ui.h
+++ /dev/null
@@ -1,552 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-#include <stdlib.h>
-
-enum {
- AUTH_NONE = 0,
- AUTH_IEEE8021X = 1,
- AUTH_WPA_PSK = 2,
- AUTH_WPA_EAP = 3,
- AUTH_WPA2_PSK = 4,
- AUTH_WPA2_EAP = 5
-};
-
-#define WPA_GUI_KEY_DATA "[key is configured]"
-
-void NetworkConfig::init()
-{
- wpagui = NULL;
- new_network = false;
-}
-
-void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
-{
- new_network = true;
-
- /* SSID BSSID frequency signal flags */
- setCaption(sel->text(0));
- ssidEdit->setText(sel->text(0));
-
- QString flags = sel->text(4);
- int auth, encr = 0;
- if (flags.find("[WPA2-EAP") >= 0)
- auth = AUTH_WPA2_EAP;
- else if (flags.find("[WPA-EAP") >= 0)
- auth = AUTH_WPA_EAP;
- else if (flags.find("[WPA2-PSK") >= 0)
- auth = AUTH_WPA2_PSK;
- else if (flags.find("[WPA-PSK") >= 0)
- auth = AUTH_WPA_PSK;
- else
- auth = AUTH_NONE;
-
- if (flags.find("-CCMP") >= 0)
- encr = 1;
- else if (flags.find("-TKIP") >= 0)
- encr = 0;
- else if (flags.find("WEP") >= 0)
- encr = 1;
- else
- encr = 0;
-
- authSelect->setCurrentItem(auth);
- authChanged(auth);
- encrSelect->setCurrentItem(encr);
-
- getEapCapa();
-}
-
-
-void NetworkConfig::authChanged(int sel)
-{
- pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
- bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
- sel == AUTH_WPA2_EAP;
- eapSelect->setEnabled(eap);
- identityEdit->setEnabled(eap);
- passwordEdit->setEnabled(eap);
- cacertEdit->setEnabled(eap);
-
- while (encrSelect->count())
- encrSelect->removeItem(0);
-
- if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
- encrSelect->insertItem("None");
- encrSelect->insertItem("WEP");
- encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1);
- } else {
- encrSelect->insertItem("TKIP");
- encrSelect->insertItem("CCMP");
- encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK ||
- sel == AUTH_WPA2_EAP) ? 1 : 0);
- }
-
- wepEnabled(sel == AUTH_IEEE8021X);
-}
-
-
-void NetworkConfig::addNetwork()
-{
- char reply[10], cmd[256];
- size_t reply_len;
- int id;
- int psklen = pskEdit->text().length();
- int auth = authSelect->currentItem();
-
- if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
- if (psklen < 8 || psklen > 64) {
- QMessageBox::warning(this, "wpa_gui", "WPA-PSK requires a passphrase "
- "of 8 to 63 characters\n"
- "or 64 hex digit PSK");
- return;
- }
- }
-
- if (wpagui == NULL)
- return;
-
- memset(reply, 0, sizeof(reply));
- reply_len = sizeof(reply) - 1;
-
- if (new_network) {
- wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
- if (reply[0] == 'F') {
- QMessageBox::warning(this, "wpa_gui", "Failed to add network to wpa_supplicant\n"
- "configuration.");
- return;
- }
- id = atoi(reply);
- } else {
- id = edit_network_id;
- }
-
- setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true);
-
- if (idstrEdit->isEnabled())
- setNetworkParam(id, "id_str", idstrEdit->text().ascii(), true);
-
- const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
- switch (auth) {
- case AUTH_NONE:
- key_mgmt = "NONE";
- break;
- case AUTH_IEEE8021X:
- key_mgmt = "IEEE8021X";
- break;
- case AUTH_WPA_PSK:
- key_mgmt = "WPA-PSK";
- proto = "WPA";
- break;
- case AUTH_WPA_EAP:
- key_mgmt = "WPA-EAP";
- proto = "WPA";
- break;
- case AUTH_WPA2_PSK:
- key_mgmt = "WPA-PSK";
- proto = "WPA2";
- break;
- case AUTH_WPA2_EAP:
- key_mgmt = "WPA-EAP";
- proto = "WPA2";
- break;
- }
-
- if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
- auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
- int encr = encrSelect->currentItem();
- if (encr == 0)
- pairwise = "TKIP";
- else
- pairwise = "CCMP";
- }
-
- if (proto)
- setNetworkParam(id, "proto", proto, false);
- if (key_mgmt)
- setNetworkParam(id, "key_mgmt", key_mgmt, false);
- if (pairwise) {
- setNetworkParam(id, "pairwise", pairwise, false);
- setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
- }
- if (pskEdit->isEnabled() &&
- strcmp(pskEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
- setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64);
- if (eapSelect->isEnabled())
- setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false);
- if (identityEdit->isEnabled())
- setNetworkParam(id, "identity", identityEdit->text().ascii(), true);
- if (passwordEdit->isEnabled() &&
- strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
- setNetworkParam(id, "password", passwordEdit->text().ascii(), true);
- if (cacertEdit->isEnabled())
- setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true);
- writeWepKey(id, wep0Edit, 0);
- writeWepKey(id, wep1Edit, 1);
- writeWepKey(id, wep2Edit, 2);
- writeWepKey(id, wep3Edit, 3);
-
- if (wep0Radio->isEnabled() && wep0Radio->isChecked())
- setNetworkParam(id, "wep_tx_keyidx", "0", false);
- else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
- setNetworkParam(id, "wep_tx_keyidx", "1", false);
- else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
- setNetworkParam(id, "wep_tx_keyidx", "2", false);
- else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
- setNetworkParam(id, "wep_tx_keyidx", "3", false);
-
- snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
- reply_len = sizeof(reply);
- wpagui->ctrlRequest(cmd, reply, &reply_len);
- if (strncmp(reply, "OK", 2) != 0) {
- QMessageBox::warning(this, "wpa_gui", "Failed to enable network in wpa_supplicant\n"
- "configuration.");
- /* Network was added, so continue anyway */
- }
- wpagui->triggerUpdate();
- wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
-
- close();
-}
-
-
-void NetworkConfig::setWpaGui( WpaGui *_wpagui )
-{
- wpagui = _wpagui;
-}
-
-
-int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote)
-{
- char reply[10], cmd[256];
- size_t reply_len;
- snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
- id, field, quote ? "\"" : "", value, quote ? "\"" : "");
- reply_len = sizeof(reply);
- wpagui->ctrlRequest(cmd, reply, &reply_len);
- return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
-}
-
-
-void NetworkConfig::encrChanged( const QString &sel )
-{
- wepEnabled(sel.find("WEP") == 0);
-}
-
-
-void NetworkConfig::wepEnabled( bool enabled )
-{
- wep0Edit->setEnabled(enabled);
- wep1Edit->setEnabled(enabled);
- wep2Edit->setEnabled(enabled);
- wep3Edit->setEnabled(enabled);
- wep0Radio->setEnabled(enabled);
- wep1Radio->setEnabled(enabled);
- wep2Radio->setEnabled(enabled);
- wep3Radio->setEnabled(enabled);
-}
-
-
-void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id )
-{
- char buf[10];
- bool hex;
- const char *txt, *pos;
- size_t len;
-
- if (!edit->isEnabled() || edit->text().isEmpty())
- return;
-
- /*
- * Assume hex key if only hex characters are present and length matches
- * with 40, 104, or 128-bit key
- */
- txt = edit->text().ascii();
- if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
- return;
- len = strlen(txt);
- if (len == 0)
- return;
- pos = txt;
- hex = true;
- while (*pos) {
- if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') ||
- (*pos >= 'A' && *pos <= 'F'))) {
- hex = false;
- break;
- }
- pos++;
- }
- if (hex && len != 10 && len != 26 && len != 32)
- hex = false;
- snprintf(buf, sizeof(buf), "wep_key%d", id);
- setNetworkParam(network_id, buf, txt, !hex);
-}
-
-
-static int key_value_isset(const char *reply, size_t reply_len)
-{
- return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
-}
-
-
-void NetworkConfig::paramsFromConfig( int network_id )
-{
- int i, res;
-
- edit_network_id = network_id;
- getEapCapa();
-
- char reply[1024], cmd[256], *pos;
- size_t reply_len;
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- ssidEdit->setText(reply + 1);
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- idstrEdit->setText(reply + 1);
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
- reply_len = sizeof(reply) - 1;
- int wpa = 0;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
- reply[reply_len] = '\0';
- if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
- wpa = 2;
- else if (strstr(reply, "WPA"))
- wpa = 1;
- }
-
- int auth = AUTH_NONE, encr = 0;
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
- reply[reply_len] = '\0';
- if (strstr(reply, "WPA-EAP"))
- auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
- else if (strstr(reply, "WPA-PSK"))
- auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
- else if (strstr(reply, "IEEE8021X")) {
- auth = AUTH_IEEE8021X;
- encr = 1;
- }
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
- reply[reply_len] = '\0';
- if (strstr(reply, "CCMP") && auth != AUTH_NONE)
- encr = 1;
- else if (strstr(reply, "TKIP"))
- encr = 0;
- else if (strstr(reply, "WEP"))
- encr = 1;
- else
- encr = 0;
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
- reply_len = sizeof(reply) - 1;
- res = wpagui->ctrlRequest(cmd, reply, &reply_len);
- if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- pskEdit->setText(reply + 1);
- } else if (res >= 0 && key_value_isset(reply, reply_len)) {
- pskEdit->setText(WPA_GUI_KEY_DATA);
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- identityEdit->setText(reply + 1);
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
- reply_len = sizeof(reply) - 1;
- res = wpagui->ctrlRequest(cmd, reply, &reply_len);
- if (res >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- passwordEdit->setText(reply + 1);
- } else if (res >= 0 && key_value_isset(reply, reply_len)) {
- passwordEdit->setText(WPA_GUI_KEY_DATA);
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- cacertEdit->setText(reply + 1);
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
- reply[reply_len] = '\0';
- for (i = 0; i < eapSelect->count(); i++) {
- if (eapSelect->text(i).compare(reply) == 0) {
- eapSelect->setCurrentItem(i);
- break;
- }
- }
- }
-
- for (i = 0; i < 4; i++) {
- QLineEdit *wepEdit;
- switch (i) {
- default:
- case 0:
- wepEdit = wep0Edit;
- break;
- case 1:
- wepEdit = wep1Edit;
- break;
- case 2:
- wepEdit = wep2Edit;
- break;
- case 3:
- wepEdit = wep3Edit;
- break;
- }
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i);
- reply_len = sizeof(reply) - 1;
- res = wpagui->ctrlRequest(cmd, reply, &reply_len);
- if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
- reply[reply_len] = '\0';
- pos = strchr(reply + 1, '"');
- if (pos)
- *pos = '\0';
- if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
- encr = 1;
-
- wepEdit->setText(reply + 1);
- } else if (res >= 0 && key_value_isset(reply, reply_len)) {
- if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
- encr = 1;
- wepEdit->setText(WPA_GUI_KEY_DATA);
- }
- }
-
- snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
- reply[reply_len] = '\0';
- switch (atoi(reply)) {
- case 0:
- wep0Radio->setChecked(true);
- break;
- case 1:
- wep1Radio->setChecked(true);
- break;
- case 2:
- wep2Radio->setChecked(true);
- break;
- case 3:
- wep3Radio->setChecked(true);
- break;
- }
- }
-
- authSelect->setCurrentItem(auth);
- authChanged(auth);
- encrSelect->setCurrentItem(encr);
- if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
- wepEnabled(encr == 1);
-
- removeButton->setEnabled(true);
- addButton->setText("Save");
-}
-
-
-void NetworkConfig::removeNetwork()
-{
- char reply[10], cmd[256];
- size_t reply_len;
-
- if (QMessageBox::information(this, "wpa_gui",
- "This will permanently remove the network\n"
- "from the configuration. Do you really want\n"
- "to remove this network?", "Yes", "No") != 0)
- return;
-
- snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
- reply_len = sizeof(reply);
- wpagui->ctrlRequest(cmd, reply, &reply_len);
- if (strncmp(reply, "OK", 2) != 0) {
- QMessageBox::warning(this, "wpa_gui",
- "Failed to remove network from wpa_supplicant\n"
- "configuration.");
- } else {
- wpagui->triggerUpdate();
- wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
- }
-
- close();
-}
-
-
-void NetworkConfig::newNetwork()
-{
- new_network = true;
- getEapCapa();
-}
-
-
-void NetworkConfig::getEapCapa()
-{
- char reply[256];
- size_t reply_len;
-
- if (wpagui == NULL)
- return;
-
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
- return;
- reply[reply_len] = '\0';
-
- QString res(reply);
- QStringList types = QStringList::split(QChar(' '), res);
- eapSelect->insertStringList(types);
-}
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui b/wpa_supplicant/wpa_gui/scanresults.ui
deleted file mode 100644
index dea305b..0000000
--- a/wpa_supplicant/wpa_gui/scanresults.ui
+++ /dev/null
@@ -1,179 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>ScanResults</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>ScanResults</cstring>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>452</width>
- <height>225</height>
- </rect>
- </property>
- <property name="caption">
- <string>Scan results</string>
- </property>
- <vbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QListView">
- <column>
- <property name="text">
- <string>SSID</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>BSSID</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>frequency</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>signal</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>flags</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <property name="name">
- <cstring>scanResultsView</cstring>
- </property>
- <property name="frameShape">
- <enum>StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>Sunken</enum>
- </property>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout24</cstring>
- </property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <spacer>
- <property name="name">
- <cstring>spacer6</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>50</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton">
- <property name="name">
- <cstring>scanButton</cstring>
- </property>
- <property name="text">
- <string>Scan</string>
- </property>
- </widget>
- <widget class="QPushButton">
- <property name="name">
- <cstring>closeButton</cstring>
- </property>
- <property name="text">
- <string>Close</string>
- </property>
- </widget>
- </hbox>
- </widget>
- </vbox>
-</widget>
-<connections>
- <connection>
- <sender>closeButton</sender>
- <signal>clicked()</signal>
- <receiver>ScanResults</receiver>
- <slot>close()</slot>
- </connection>
- <connection>
- <sender>scanButton</sender>
- <signal>clicked()</signal>
- <receiver>ScanResults</receiver>
- <slot>scanRequest()</slot>
- </connection>
- <connection>
- <sender>scanResultsView</sender>
- <signal>doubleClicked(QListViewItem*)</signal>
- <receiver>ScanResults</receiver>
- <slot>bssSelected(QListViewItem*)</slot>
- </connection>
-</connections>
-<includes>
- <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
- <include location="local" impldecl="in implementation">wpagui.h</include>
- <include location="local" impldecl="in implementation">networkconfig.h</include>
- <include location="local" impldecl="in implementation">scanresults.ui.h</include>
-</includes>
-<forwards>
- <forward>class WpaGui;</forward>
-</forwards>
-<variables>
- <variable access="private">WpaGui *wpagui;</variable>
- <variable access="private">QTimer *timer;</variable>
-</variables>
-<slots>
- <slot>setWpaGui( WpaGui * _wpagui )</slot>
- <slot>updateResults()</slot>
- <slot>scanRequest()</slot>
- <slot>getResults()</slot>
- <slot>bssSelected( QListViewItem * sel )</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui.h b/wpa_supplicant/wpa_gui/scanresults.ui.h
deleted file mode 100644
index 530d2e6..0000000
--- a/wpa_supplicant/wpa_gui/scanresults.ui.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-void ScanResults::init()
-{
- wpagui = NULL;
-}
-
-
-void ScanResults::destroy()
-{
- delete timer;
-}
-
-
-void ScanResults::setWpaGui(WpaGui *_wpagui)
-{
- wpagui = _wpagui;
- updateResults();
-
- timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), SLOT(getResults()));
- timer->start(10000, FALSE);
-}
-
-
-void ScanResults::updateResults()
-{
- char reply[8192];
- size_t reply_len;
-
- if (wpagui == NULL)
- return;
-
- reply_len = sizeof(reply) - 1;
- if (wpagui->ctrlRequest("SCAN_RESULTS", reply, &reply_len) < 0)
- return;
- reply[reply_len] = '\0';
-
- scanResultsView->clear();
-
- QString res(reply);
- QStringList lines = QStringList::split(QChar('\n'), res);
- bool first = true;
- for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) {
- if (first) {
- first = false;
- continue;
- }
-
- QStringList cols = QStringList::split(QChar('\t'), *it, true);
- QString ssid, bssid, freq, signal, flags;
- bssid = cols.count() > 0 ? cols[0] : "";
- freq = cols.count() > 1 ? cols[1] : "";
- signal = cols.count() > 2 ? cols[2] : "";
- flags = cols.count() > 3 ? cols[3] : "";
- ssid = cols.count() > 4 ? cols[4] : "";
- new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal, flags);
- }
-}
-
-
-void ScanResults::scanRequest()
-{
- char reply[10];
- size_t reply_len = sizeof(reply);
-
- if (wpagui == NULL)
- return;
-
- wpagui->ctrlRequest("SCAN", reply, &reply_len);
-}
-
-
-void ScanResults::getResults()
-{
- updateResults();
-}
-
-
-
-
-void ScanResults::bssSelected( Q3ListViewItem * sel )
-{
- NetworkConfig *nc = new NetworkConfig();
- if (nc == NULL)
- return;
- nc->setWpaGui(wpagui);
- nc->paramsFromScanResults(sel);
- nc->show();
- nc->exec();
-}
diff --git a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
deleted file mode 100755
index e173b00..0000000
--- a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-# qmake seems to be forcing include and lib paths from the original build
-# and I have no idea how to change these. For now, just override the
-# directories in the Makefile.Release file after qmake run.
-
-qmake -spec /q/jm/qt4-win/4.0.0/mkspecs/win32-g++ wpa_gui.pro -o Makefile
-cat Makefile.Release |
- sed s%qt4/lib%qt4-win/4.0.0/lib%g |
- sed s%qt4/include%qt4-win/4.0.0/include%g > tmp.Makefile.Release &&
-mv -f tmp.Makefile.Release Makefile.Release
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui b/wpa_supplicant/wpa_gui/userdatarequest.ui
deleted file mode 100644
index 6106b1e..0000000
--- a/wpa_supplicant/wpa_gui/userdatarequest.ui
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>UserDataRequest</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>UserDataRequest</cstring>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>216</width>
- <height>103</height>
- </rect>
- </property>
- <property name="caption">
- <string>Authentication credentials required</string>
- </property>
- <property name="sizeGripEnabled">
- <bool>true</bool>
- </property>
- <vbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel">
- <property name="name">
- <cstring>queryInfo</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout28</cstring>
- </property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel">
- <property name="name">
- <cstring>queryField</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLineEdit">
- <property name="name">
- <cstring>queryEdit</cstring>
- </property>
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="echoMode">
- <enum>Password</enum>
- </property>
- </widget>
- </hbox>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout27</cstring>
- </property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <spacer>
- <property name="name">
- <cstring>spacer4</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton">
- <property name="name">
- <cstring>buttonOk</cstring>
- </property>
- <property name="text">
- <string>&amp;OK</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- <property name="autoDefault">
- <bool>true</bool>
- </property>
- <property name="default">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QPushButton">
- <property name="name">
- <cstring>buttonCancel</cstring>
- </property>
- <property name="text">
- <string>&amp;Cancel</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- <property name="autoDefault">
- <bool>true</bool>
- </property>
- </widget>
- </hbox>
- </widget>
- </vbox>
-</widget>
-<connections>
- <connection>
- <sender>buttonOk</sender>
- <signal>clicked()</signal>
- <receiver>UserDataRequest</receiver>
- <slot>sendReply()</slot>
- </connection>
- <connection>
- <sender>buttonCancel</sender>
- <signal>clicked()</signal>
- <receiver>UserDataRequest</receiver>
- <slot>reject()</slot>
- </connection>
- <connection>
- <sender>queryEdit</sender>
- <signal>returnPressed()</signal>
- <receiver>UserDataRequest</receiver>
- <slot>sendReply()</slot>
- </connection>
-</connections>
-<includes>
- <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
- <include location="local" impldecl="in implementation">wpagui.h</include>
- <include location="local" impldecl="in implementation">userdatarequest.ui.h</include>
-</includes>
-<forwards>
- <forward>class WpaGui;</forward>
-</forwards>
-<variables>
- <variable access="private">WpaGui *wpagui;</variable>
- <variable access="private">int networkid;</variable>
- <variable access="private">QString field;</variable>
-</variables>
-<slots>
- <slot>sendReply()</slot>
-</slots>
-<functions>
- <function specifier="non virtual" returnType="int">setParams( WpaGui * _wpagui, const char * reqMsg )</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/wpa_supplicant/wpa_gui/userdatarequest.ui.h
deleted file mode 100644
index 66d4478..0000000
--- a/wpa_supplicant/wpa_gui/userdatarequest.ui.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-#include <stdlib.h>
-
-int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
-{
- char *tmp, *pos, *pos2;
- wpagui = _wpagui;
- tmp = strdup(reqMsg);
- if (tmp == NULL)
- return -1;
- pos = strchr(tmp, '-');
- if (pos == NULL) {
- free(tmp);
- return -1;
- }
- *pos++ = '\0';
- field = tmp;
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- free(tmp);
- return -1;
- }
- *pos2++ = '\0';
-
- networkid = atoi(pos);
- queryInfo->setText(pos2);
- if (strcmp(tmp, "PASSWORD") == 0) {
- queryField->setText("Password: ");
- queryEdit->setEchoMode(QLineEdit::Password);
- } else if (strcmp(tmp, "NEW_PASSWORD") == 0) {
- queryField->setText("New password: ");
- queryEdit->setEchoMode(QLineEdit::Password);
- } else if (strcmp(tmp, "IDENTITY") == 0)
- queryField->setText("Identity: ");
- else if (strcmp(tmp, "PASSPHRASE") == 0) {
- queryField->setText("Private key passphrase: ");
- queryEdit->setEchoMode(QLineEdit::Password);
- } else
- queryField->setText(field + ":");
- free(tmp);
-
- return 0;
-}
-
-
-void UserDataRequest::sendReply()
-{
- char reply[10];
- size_t reply_len = sizeof(reply);
-
- if (wpagui == NULL) {
- reject();
- return;
- }
-
- QString cmd = QString(WPA_CTRL_RSP) + field + '-' +
- QString::number(networkid) + ':' +
- queryEdit->text();
- wpagui->ctrlRequest(cmd.ascii(), reply, &reply_len);
- accept();
-}
diff --git a/wpa_supplicant/wpa_gui/wpa_gui.pro b/wpa_supplicant/wpa_gui/wpa_gui.pro
deleted file mode 100644
index a42a4ac..0000000
--- a/wpa_supplicant/wpa_gui/wpa_gui.pro
+++ /dev/null
@@ -1,50 +0,0 @@
-TEMPLATE = app
-LANGUAGE = C++
-
-CONFIG += qt warn_on release
-
-DEFINES += CONFIG_CTRL_IFACE
-
-win32 {
- LIBS += -lws2_32 -static
- DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
- SOURCES += ../../src/utils/os_win32.c
-} else:win32-g++ {
- # cross compilation to win32
- LIBS += -lws2_32 -static
- DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
- SOURCES += ../../src/utils/os_win32.c
-} else {
- DEFINES += CONFIG_CTRL_IFACE_UNIX
- SOURCES += ../../src/utils/os_unix.c
-}
-
-INCLUDEPATH += . .. ../../src ../../src/utils
-
-HEADERS += wpamsg.h
-
-SOURCES += main.cpp \
- ../../src/common/wpa_ctrl.c
-
-FORMS = wpagui.ui \
- eventhistory.ui \
- scanresults.ui \
- userdatarequest.ui \
- networkconfig.ui
-
-
-unix {
- UI_DIR = .ui
- MOC_DIR = .moc
- OBJECTS_DIR = .obj
-}
-
-qtver = $$[QT_VERSION]
-isEmpty( qtver ) {
- message(Compiling for Qt 3.x)
- DEFINES += Q3ListViewItem=QListViewItem
-} else {
- message(Compiling for Qt $$qtver)
- QT += qt3support
- CONFIG += uic3
-}
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui b/wpa_supplicant/wpa_gui/wpagui.ui
deleted file mode 100644
index b49d96b..0000000
--- a/wpa_supplicant/wpa_gui/wpagui.ui
+++ /dev/null
@@ -1,471 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>WpaGui</class>
-<widget class="QMainWindow">
- <property name="name">
- <cstring>WpaGui</cstring>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>279</width>
- <height>308</height>
- </rect>
- </property>
- <property name="caption">
- <string>wpa_gui</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
- <property name="name">
- <cstring>textLabel16</cstring>
- </property>
- <property name="text">
- <string>Adapter:</string>
- </property>
- </widget>
- <widget class="QComboBox" row="0" column="2" rowspan="1" colspan="2">
- <property name="name">
- <cstring>adapterSelect</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
- <property name="name">
- <cstring>textLabel8</cstring>
- </property>
- <property name="text">
- <string>Network:</string>
- </property>
- </widget>
- <widget class="QComboBox" row="1" column="2" rowspan="1" colspan="2">
- <property name="name">
- <cstring>networkSelect</cstring>
- </property>
- </widget>
- <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
- <property name="name">
- <cstring>frame3</cstring>
- </property>
- <property name="frameShape">
- <enum>StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>Raised</enum>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel" row="0" column="0">
- <property name="name">
- <cstring>textLabel1</cstring>
- </property>
- <property name="text">
- <string>Status:</string>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="0">
- <property name="name">
- <cstring>textLabel2</cstring>
- </property>
- <property name="text">
- <string>Last message:</string>
- </property>
- </widget>
- <widget class="QLabel" row="2" column="0">
- <property name="name">
- <cstring>textLabel3</cstring>
- </property>
- <property name="text">
- <string>Authentication:</string>
- </property>
- </widget>
- <widget class="QLabel" row="3" column="0">
- <property name="name">
- <cstring>textLabel4</cstring>
- </property>
- <property name="text">
- <string>Encryption:</string>
- </property>
- </widget>
- <widget class="QLabel" row="4" column="0">
- <property name="name">
- <cstring>textLabel5</cstring>
- </property>
- <property name="text">
- <string>SSID:</string>
- </property>
- </widget>
- <widget class="QLabel" row="5" column="0">
- <property name="name">
- <cstring>textLabel6</cstring>
- </property>
- <property name="text">
- <string>BSSID:</string>
- </property>
- </widget>
- <widget class="QLabel" row="6" column="0">
- <property name="name">
- <cstring>textLabel7</cstring>
- </property>
- <property name="text">
- <string>IP address:</string>
- </property>
- </widget>
- <widget class="QLabel" row="0" column="1">
- <property name="name">
- <cstring>textStatus</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3">
- <property name="name">
- <cstring>textLastMessage</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="2" column="1">
- <property name="name">
- <cstring>textAuthentication</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="3" column="1">
- <property name="name">
- <cstring>textEncryption</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="4" column="1">
- <property name="name">
- <cstring>textSsid</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="5" column="1">
- <property name="name">
- <cstring>textBssid</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="6" column="1">
- <property name="name">
- <cstring>textIpAddress</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- </grid>
- </widget>
- <spacer row="3" column="0">
- <property name="name">
- <cstring>spacer7</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton" row="3" column="1">
- <property name="name">
- <cstring>connectButton</cstring>
- </property>
- <property name="text">
- <string>Connect</string>
- </property>
- </widget>
- <widget class="QPushButton" row="3" column="2">
- <property name="name">
- <cstring>disconnectButton</cstring>
- </property>
- <property name="text">
- <string>Disconnect</string>
- </property>
- </widget>
- <widget class="QPushButton" row="3" column="3">
- <property name="name">
- <cstring>scanButton</cstring>
- </property>
- <property name="text">
- <string>Scan</string>
- </property>
- </widget>
- </grid>
-</widget>
-<menubar>
- <property name="name">
- <cstring>MenuBar</cstring>
- </property>
- <item text="&amp;File" name="fileMenu">
- <separator/>
- <action name="fileEventHistoryAction"/>
- <action name="fileAdd_NetworkAction"/>
- <action name="fileEdit_networkAction"/>
- <separator/>
- <action name="fileExitAction"/>
- </item>
- <item text="&amp;Help" name="helpMenu">
- <action name="helpContentsAction"/>
- <action name="helpIndexAction"/>
- <separator/>
- <action name="helpAboutAction"/>
- </item>
-</menubar>
-<toolbars>
-</toolbars>
-<actions>
- <action>
- <property name="name">
- <cstring>fileExitAction</cstring>
- </property>
- <property name="text">
- <string>Exit</string>
- </property>
- <property name="menuText">
- <string>E&amp;xit</string>
- </property>
- <property name="accel">
- <string>Ctrl+Q</string>
- </property>
- </action>
- <action>
- <property name="name">
- <cstring>helpContentsAction</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Contents</string>
- </property>
- <property name="menuText">
- <string>&amp;Contents...</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- </action>
- <action>
- <property name="name">
- <cstring>helpIndexAction</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Index</string>
- </property>
- <property name="menuText">
- <string>&amp;Index...</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- </action>
- <action>
- <property name="name">
- <cstring>helpAboutAction</cstring>
- </property>
- <property name="text">
- <string>About</string>
- </property>
- <property name="menuText">
- <string>&amp;About</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- </action>
- <action>
- <property name="name">
- <cstring>fileEventHistoryAction</cstring>
- </property>
- <property name="text">
- <string>Event History</string>
- </property>
- <property name="menuText">
- <string>Event &amp;History</string>
- </property>
- </action>
- <action>
- <property name="name">
- <cstring>fileAdd_NetworkAction</cstring>
- </property>
- <property name="text">
- <string>Add Network</string>
- </property>
- <property name="menuText">
- <string>&amp;Add Network</string>
- </property>
- </action>
- <action>
- <property name="name">
- <cstring>fileEdit_networkAction</cstring>
- </property>
- <property name="text">
- <string>Edit Network</string>
- </property>
- <property name="menuText">
- <string>&amp;Edit Network</string>
- </property>
- </action>
-</actions>
-<connections>
- <connection>
- <sender>helpIndexAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>helpIndex()</slot>
- </connection>
- <connection>
- <sender>helpContentsAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>helpContents()</slot>
- </connection>
- <connection>
- <sender>helpAboutAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>helpAbout()</slot>
- </connection>
- <connection>
- <sender>fileExitAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>close()</slot>
- </connection>
- <connection>
- <sender>disconnectButton</sender>
- <signal>clicked()</signal>
- <receiver>WpaGui</receiver>
- <slot>disconnect()</slot>
- </connection>
- <connection>
- <sender>scanButton</sender>
- <signal>clicked()</signal>
- <receiver>WpaGui</receiver>
- <slot>scan()</slot>
- </connection>
- <connection>
- <sender>connectButton</sender>
- <signal>clicked()</signal>
- <receiver>WpaGui</receiver>
- <slot>connectB()</slot>
- </connection>
- <connection>
- <sender>fileEventHistoryAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>eventHistory()</slot>
- </connection>
- <connection>
- <sender>networkSelect</sender>
- <signal>activated(const QString&amp;)</signal>
- <receiver>WpaGui</receiver>
- <slot>selectNetwork(const QString&amp;)</slot>
- </connection>
- <connection>
- <sender>fileEdit_networkAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>editNetwork()</slot>
- </connection>
- <connection>
- <sender>fileAdd_NetworkAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>addNetwork()</slot>
- </connection>
- <connection>
- <sender>adapterSelect</sender>
- <signal>activated(const QString&amp;)</signal>
- <receiver>WpaGui</receiver>
- <slot>selectAdapter(const QString&amp;)</slot>
- </connection>
-</connections>
-<includes>
- <include location="global" impldecl="in declaration">qtimer.h</include>
- <include location="global" impldecl="in declaration">qsocketnotifier.h</include>
- <include location="local" impldecl="in declaration">wpamsg.h</include>
- <include location="local" impldecl="in declaration">eventhistory.h</include>
- <include location="local" impldecl="in declaration">scanresults.h</include>
- <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
- <include location="global" impldecl="in implementation">dirent.h</include>
- <include location="global" impldecl="in implementation">qmessagebox.h</include>
- <include location="global" impldecl="in implementation">qapplication.h</include>
- <include location="local" impldecl="in implementation">userdatarequest.h</include>
- <include location="local" impldecl="in implementation">networkconfig.h</include>
- <include location="local" impldecl="in implementation">wpagui.ui.h</include>
-</includes>
-<forwards>
- <forward>class UserDataRequest;</forward>
-</forwards>
-<variables>
- <variable access="private">ScanResults *scanres;</variable>
- <variable access="private">bool networkMayHaveChanged;</variable>
- <variable access="private">char *ctrl_iface;</variable>
- <variable access="private">EventHistory *eh;</variable>
- <variable access="private">struct wpa_ctrl *ctrl_conn;</variable>
- <variable access="private">QSocketNotifier *msgNotifier;</variable>
- <variable access="private">QTimer *timer;</variable>
- <variable access="private">int pingsToStatusUpdate;</variable>
- <variable access="private">WpaMsgList msgs;</variable>
- <variable access="private">char *ctrl_iface_dir;</variable>
- <variable access="private">struct wpa_ctrl *monitor_conn;</variable>
- <variable access="private">UserDataRequest *udr;</variable>
-</variables>
-<slots>
- <slot>parse_argv()</slot>
- <slot>updateStatus()</slot>
- <slot>updateNetworks()</slot>
- <slot>helpIndex()</slot>
- <slot>helpContents()</slot>
- <slot>helpAbout()</slot>
- <slot>disconnect()</slot>
- <slot>scan()</slot>
- <slot>eventHistory()</slot>
- <slot>ping()</slot>
- <slot>processMsg( char * msg )</slot>
- <slot>processCtrlReq( const char * req )</slot>
- <slot>receiveMsgs()</slot>
- <slot>connectB()</slot>
- <slot>selectNetwork( const QString &amp; sel )</slot>
- <slot>editNetwork()</slot>
- <slot>addNetwork()</slot>
- <slot>selectAdapter( const QString &amp; sel )</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function access="private" specifier="non virtual">destroy()</function>
- <function access="private" specifier="non virtual" returnType="int">openCtrlConnection( const char * ifname )</function>
- <function returnType="int">ctrlRequest( const char * cmd, char * buf, size_t * buflen )</function>
- <function>triggerUpdate()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui.h b/wpa_supplicant/wpa_gui/wpagui.ui.h
deleted file mode 100644
index 678ff1b..0000000
--- a/wpa_supplicant/wpa_gui/wpagui.ui.h
+++ /dev/null
@@ -1,730 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
-
-#include <stdlib.h>
-
-void WpaGui::init()
-{
- eh = NULL;
- scanres = NULL;
- udr = NULL;
- ctrl_iface = NULL;
- ctrl_conn = NULL;
- monitor_conn = NULL;
- msgNotifier = NULL;
- ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
-
- parse_argv();
-
- textStatus->setText("connecting to wpa_supplicant");
- timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), SLOT(ping()));
- timer->start(1000, FALSE);
-
- if (openCtrlConnection(ctrl_iface) < 0) {
- printf("Failed to open control connection to wpa_supplicant.\n");
- }
-
- updateStatus();
- networkMayHaveChanged = true;
- updateNetworks();
-}
-
-
-void WpaGui::destroy()
-{
- delete msgNotifier;
-
- if (monitor_conn) {
- wpa_ctrl_detach(monitor_conn);
- wpa_ctrl_close(monitor_conn);
- monitor_conn = NULL;
- }
- if (ctrl_conn) {
- wpa_ctrl_close(ctrl_conn);
- ctrl_conn = NULL;
- }
-
- if (eh) {
- eh->close();
- delete eh;
- eh = NULL;
- }
-
- if (scanres) {
- scanres->close();
- delete scanres;
- scanres = NULL;
- }
-
- if (udr) {
- udr->close();
- delete udr;
- udr = NULL;
- }
-
- free(ctrl_iface);
- ctrl_iface = NULL;
-
- free(ctrl_iface_dir);
- ctrl_iface_dir = NULL;
-}
-
-
-void WpaGui::parse_argv()
-{
- int c;
- for (;;) {
- c = getopt(qApp->argc(), qApp->argv(), "i:p:");
- if (c < 0)
- break;
- switch (c) {
- case 'i':
- free(ctrl_iface);
- ctrl_iface = strdup(optarg);
- break;
- case 'p':
- free(ctrl_iface_dir);
- ctrl_iface_dir = strdup(optarg);
- break;
- }
- }
-}
-
-
-int WpaGui::openCtrlConnection(const char *ifname)
-{
- char *cfile;
- int flen;
- char buf[2048], *pos, *pos2;
- size_t len;
-
- if (ifname) {
- if (ifname != ctrl_iface) {
- free(ctrl_iface);
- ctrl_iface = strdup(ifname);
- }
- } else {
-#ifdef CONFIG_CTRL_IFACE_UDP
- free(ctrl_iface);
- ctrl_iface = strdup("udp");
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#ifdef CONFIG_CTRL_IFACE_UNIX
- struct dirent *dent;
- DIR *dir = opendir(ctrl_iface_dir);
- free(ctrl_iface);
- ctrl_iface = NULL;
- if (dir) {
- while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
- /* Skip the file if it is not a socket.
- * Also accept DT_UNKNOWN (0) in case
- * the C library or underlying file
- * system does not support d_type. */
- if (dent->d_type != DT_SOCK &&
- dent->d_type != DT_UNKNOWN)
- continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-
- if (strcmp(dent->d_name, ".") == 0 ||
- strcmp(dent->d_name, "..") == 0)
- continue;
- printf("Selected interface '%s'\n", dent->d_name);
- ctrl_iface = strdup(dent->d_name);
- break;
- }
- closedir(dir);
- }
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- struct wpa_ctrl *ctrl;
- int ret;
-
- free(ctrl_iface);
- ctrl_iface = NULL;
-
- ctrl = wpa_ctrl_open(NULL);
- if (ctrl) {
- len = sizeof(buf) - 1;
- ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
- if (ret >= 0) {
- buf[len] = '\0';
- pos = strchr(buf, '\n');
- if (pos)
- *pos = '\0';
- ctrl_iface = strdup(buf);
- }
- wpa_ctrl_close(ctrl);
- }
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- }
-
- if (ctrl_iface == NULL)
- return -1;
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
- flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
- cfile = (char *) malloc(flen);
- if (cfile == NULL)
- return -1;
- snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
-#else /* CONFIG_CTRL_IFACE_UNIX */
- flen = strlen(ctrl_iface) + 1;
- cfile = (char *) malloc(flen);
- if (cfile == NULL)
- return -1;
- snprintf(cfile, flen, "%s", ctrl_iface);
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-
- if (ctrl_conn) {
- wpa_ctrl_close(ctrl_conn);
- ctrl_conn = NULL;
- }
-
- if (monitor_conn) {
- delete msgNotifier;
- msgNotifier = NULL;
- wpa_ctrl_detach(monitor_conn);
- wpa_ctrl_close(monitor_conn);
- monitor_conn = NULL;
- }
-
- printf("Trying to connect to '%s'\n", cfile);
- ctrl_conn = wpa_ctrl_open(cfile);
- if (ctrl_conn == NULL) {
- free(cfile);
- return -1;
- }
- monitor_conn = wpa_ctrl_open(cfile);
- free(cfile);
- if (monitor_conn == NULL) {
- wpa_ctrl_close(ctrl_conn);
- return -1;
- }
- if (wpa_ctrl_attach(monitor_conn)) {
- printf("Failed to attach to wpa_supplicant\n");
- wpa_ctrl_close(monitor_conn);
- monitor_conn = NULL;
- wpa_ctrl_close(ctrl_conn);
- ctrl_conn = NULL;
- return -1;
- }
-
-#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
- msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
- QSocketNotifier::Read, this);
- connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
-#endif
-
- adapterSelect->clear();
- adapterSelect->insertItem(ctrl_iface);
- adapterSelect->setCurrentItem(0);
-
- len = sizeof(buf) - 1;
- if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) {
- buf[len] = '\0';
- pos = buf;
- while (*pos) {
- pos2 = strchr(pos, '\n');
- if (pos2)
- *pos2 = '\0';
- if (strcmp(pos, ctrl_iface) != 0)
- adapterSelect->insertItem(pos);
- if (pos2)
- pos = pos2 + 1;
- else
- break;
- }
- }
-
- return 0;
-}
-
-
-static void wpa_gui_msg_cb(char *msg, size_t)
-{
- /* This should not happen anymore since two control connections are used. */
- printf("missed message: %s\n", msg);
-}
-
-
-int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
-{
- int ret;
-
- if (ctrl_conn == NULL)
- return -3;
- ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
- wpa_gui_msg_cb);
- if (ret == -2) {
- printf("'%s' command timed out.\n", cmd);
- } else if (ret < 0) {
- printf("'%s' command failed.\n", cmd);
- }
-
- return ret;
-}
-
-
-void WpaGui::updateStatus()
-{
- char buf[2048], *start, *end, *pos;
- size_t len;
-
- pingsToStatusUpdate = 10;
-
- len = sizeof(buf) - 1;
- if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
- textStatus->setText("Could not get status from wpa_supplicant");
- textAuthentication->clear();
- textEncryption->clear();
- textSsid->clear();
- textBssid->clear();
- textIpAddress->clear();
- return;
- }
-
- buf[len] = '\0';
-
- bool auth_updated = false, ssid_updated = false;
- bool bssid_updated = false, ipaddr_updated = false;
- bool status_updated = false;
- char *pairwise_cipher = NULL, *group_cipher = NULL;
-
- start = buf;
- while (*start) {
- bool last = false;
- end = strchr(start, '\n');
- if (end == NULL) {
- last = true;
- end = start;
- while (end[0] && end[1])
- end++;
- }
- *end = '\0';
-
- pos = strchr(start, '=');
- if (pos) {
- *pos++ = '\0';
- if (strcmp(start, "bssid") == 0) {
- bssid_updated = true;
- textBssid->setText(pos);
- } else if (strcmp(start, "ssid") == 0) {
- ssid_updated = true;
- textSsid->setText(pos);
- } else if (strcmp(start, "ip_address") == 0) {
- ipaddr_updated = true;
- textIpAddress->setText(pos);
- } else if (strcmp(start, "wpa_state") == 0) {
- status_updated = true;
- textStatus->setText(pos);
- } else if (strcmp(start, "key_mgmt") == 0) {
- auth_updated = true;
- textAuthentication->setText(pos);
- /* TODO: could add EAP status to this */
- } else if (strcmp(start, "pairwise_cipher") == 0) {
- pairwise_cipher = pos;
- } else if (strcmp(start, "group_cipher") == 0) {
- group_cipher = pos;
- }
- }
-
- if (last)
- break;
- start = end + 1;
- }
-
- if (pairwise_cipher || group_cipher) {
- QString encr;
- if (pairwise_cipher && group_cipher &&
- strcmp(pairwise_cipher, group_cipher) != 0) {
- encr.append(pairwise_cipher);
- encr.append(" + ");
- encr.append(group_cipher);
- } else if (pairwise_cipher) {
- encr.append(pairwise_cipher);
- } else {
- encr.append(group_cipher);
- encr.append(" [group key only]");
- }
- textEncryption->setText(encr);
- } else
- textEncryption->clear();
-
- if (!status_updated)
- textStatus->clear();
- if (!auth_updated)
- textAuthentication->clear();
- if (!ssid_updated)
- textSsid->clear();
- if (!bssid_updated)
- textBssid->clear();
- if (!ipaddr_updated)
- textIpAddress->clear();
-}
-
-
-void WpaGui::updateNetworks()
-{
- char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
- size_t len;
- int first_active = -1;
- bool selected = false;
-
- if (!networkMayHaveChanged)
- return;
-
- networkSelect->clear();
-
- if (ctrl_conn == NULL)
- return;
-
- len = sizeof(buf) - 1;
- if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
- return;
-
- buf[len] = '\0';
- start = strchr(buf, '\n');
- if (start == NULL)
- return;
- start++;
-
- while (*start) {
- bool last = false;
- end = strchr(start, '\n');
- if (end == NULL) {
- last = true;
- end = start;
- while (end[0] && end[1])
- end++;
- }
- *end = '\0';
-
- id = start;
- ssid = strchr(id, '\t');
- if (ssid == NULL)
- break;
- *ssid++ = '\0';
- bssid = strchr(ssid, '\t');
- if (bssid == NULL)
- break;
- *bssid++ = '\0';
- flags = strchr(bssid, '\t');
- if (flags == NULL)
- break;
- *flags++ = '\0';
-
- QString network(id);
- network.append(": ");
- network.append(ssid);
- networkSelect->insertItem(network);
-
- if (strstr(flags, "[CURRENT]")) {
- networkSelect->setCurrentItem(networkSelect->count() - 1);
- selected = true;
- } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL)
- first_active = networkSelect->count() - 1;
-
- if (last)
- break;
- start = end + 1;
- }
-
- if (!selected && first_active >= 0)
- networkSelect->setCurrentItem(first_active);
-
- networkMayHaveChanged = false;
-}
-
-
-void WpaGui::helpIndex()
-{
- printf("helpIndex\n");
-}
-
-
-void WpaGui::helpContents()
-{
- printf("helpContents\n");
-}
-
-
-void WpaGui::helpAbout()
-{
- QMessageBox::about(this, "wpa_gui for wpa_supplicant",
- "Copyright (c) 2003-2008,\n"
- "Jouni Malinen <j@w1.fi>\n"
- "and contributors.\n"
- "\n"
- "This program is free software. You can\n"
- "distribute it and/or modify it under the terms of\n"
- "the GNU General Public License version 2.\n"
- "\n"
- "Alternatively, this software may be distributed\n"
- "under the terms of the BSD license.\n"
- "\n"
- "This product includes software developed\n"
- "by the OpenSSL Project for use in the\n"
- "OpenSSL Toolkit (http://www.openssl.org/)\n");
-}
-
-
-void WpaGui::disconnect()
-{
- char reply[10];
- size_t reply_len = sizeof(reply);
- ctrlRequest("DISCONNECT", reply, &reply_len);
-}
-
-
-void WpaGui::scan()
-{
- if (scanres) {
- scanres->close();
- delete scanres;
- }
-
- scanres = new ScanResults();
- if (scanres == NULL)
- return;
- scanres->setWpaGui(this);
- scanres->show();
- scanres->exec();
-}
-
-
-void WpaGui::eventHistory()
-{
- if (eh) {
- eh->close();
- delete eh;
- }
-
- eh = new EventHistory();
- if (eh == NULL)
- return;
- eh->addEvents(msgs);
- eh->show();
- eh->exec();
-}
-
-
-void WpaGui::ping()
-{
- char buf[10];
- size_t len;
-
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- /*
- * QSocketNotifier cannot be used with Windows named pipes, so use a timer
- * to check for received messages for now. This could be optimized be doing
- * something specific to named pipes or Windows events, but it is not clear
- * what would be the best way of doing that in Qt.
- */
- receiveMsgs();
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-
- if (scanres && !scanres->isVisible()) {
- delete scanres;
- scanres = NULL;
- }
-
- if (eh && !eh->isVisible()) {
- delete eh;
- eh = NULL;
- }
-
- if (udr && !udr->isVisible()) {
- delete udr;
- udr = NULL;
- }
-
- len = sizeof(buf) - 1;
- if (ctrlRequest("PING", buf, &len) < 0) {
- printf("PING failed - trying to reconnect\n");
- if (openCtrlConnection(ctrl_iface) >= 0) {
- printf("Reconnected successfully\n");
- pingsToStatusUpdate = 0;
- }
- }
-
- pingsToStatusUpdate--;
- if (pingsToStatusUpdate <= 0) {
- updateStatus();
- updateNetworks();
- }
-}
-
-
-static int str_match(const char *a, const char *b)
-{
- return strncmp(a, b, strlen(b)) == 0;
-}
-
-
-void WpaGui::processMsg(char *msg)
-{
- char *pos = msg, *pos2;
- int priority = 2;
-
- if (*pos == '<') {
- /* skip priority */
- pos++;
- priority = atoi(pos);
- pos = strchr(pos, '>');
- if (pos)
- pos++;
- else
- pos = msg;
- }
-
- WpaMsg wm(pos, priority);
- if (eh)
- eh->addEvent(wm);
- msgs.append(wm);
- while (msgs.count() > 100)
- msgs.pop_front();
-
- /* Update last message with truncated version of the event */
- if (strncmp(pos, "CTRL-", 5) == 0) {
- pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
- if (pos2)
- pos2++;
- else
- pos2 = pos;
- } else
- pos2 = pos;
- QString lastmsg = pos2;
- lastmsg.truncate(40);
- textLastMessage->setText(lastmsg);
-
- pingsToStatusUpdate = 0;
- networkMayHaveChanged = true;
-
- if (str_match(pos, WPA_CTRL_REQ))
- processCtrlReq(pos + strlen(WPA_CTRL_REQ));
-}
-
-
-void WpaGui::processCtrlReq(const char *req)
-{
- if (udr) {
- udr->close();
- delete udr;
- }
- udr = new UserDataRequest();
- if (udr == NULL)
- return;
- if (udr->setParams(this, req) < 0) {
- delete udr;
- udr = NULL;
- return;
- }
- udr->show();
- udr->exec();
-}
-
-
-void WpaGui::receiveMsgs()
-{
- char buf[256];
- size_t len;
-
- while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
- len = sizeof(buf) - 1;
- if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
- buf[len] = '\0';
- processMsg(buf);
- }
- }
-}
-
-
-void WpaGui::connectB()
-{
- char reply[10];
- size_t reply_len = sizeof(reply);
- ctrlRequest("REASSOCIATE", reply, &reply_len);
-}
-
-
-void WpaGui::selectNetwork( const QString &sel )
-{
- QString cmd(sel);
- char reply[10];
- size_t reply_len = sizeof(reply);
-
- int pos = cmd.find(':');
- if (pos < 0) {
- printf("Invalid selectNetwork '%s'\n", cmd.ascii());
- return;
- }
- cmd.truncate(pos);
- cmd.prepend("SELECT_NETWORK ");
- ctrlRequest(cmd.ascii(), reply, &reply_len);
-}
-
-
-void WpaGui::editNetwork()
-{
- QString sel(networkSelect->currentText());
- int pos = sel.find(':');
- if (pos < 0) {
- printf("Invalid selectNetwork '%s'\n", sel.ascii());
- return;
- }
- sel.truncate(pos);
-
- NetworkConfig *nc = new NetworkConfig();
- if (nc == NULL)
- return;
- nc->setWpaGui(this);
-
- nc->paramsFromConfig(sel.toInt());
- nc->show();
- nc->exec();
-}
-
-
-void WpaGui::triggerUpdate()
-{
- updateStatus();
- networkMayHaveChanged = true;
- updateNetworks();
-}
-
-
-void WpaGui::addNetwork()
-{
- NetworkConfig *nc = new NetworkConfig();
- if (nc == NULL)
- return;
- nc->setWpaGui(this);
- nc->newNetwork();
- nc->show();
- nc->exec();
-}
-
-
-void WpaGui::selectAdapter( const QString & sel )
-{
- if (openCtrlConnection(sel.ascii()) < 0)
- printf("Failed to open control connection to wpa_supplicant.\n");
- updateStatus();
- updateNetworks();
-}
diff --git a/wpa_supplicant/wpa_gui/wpamsg.h b/wpa_supplicant/wpa_gui/wpamsg.h
deleted file mode 100644
index f3fce06..0000000
--- a/wpa_supplicant/wpa_gui/wpamsg.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef WPAMSG_H
-#define WPAMSG_H
-
-class WpaMsg;
-
-#if QT_VERSION >= 0x040000
-#include <QDateTime>
-#include <QLinkedList>
-typedef QLinkedList<WpaMsg> WpaMsgList;
-#else
-#include <qdatetime.h>
-typedef QValueList<WpaMsg> WpaMsgList;
-#endif
-
-class WpaMsg {
-public:
- WpaMsg() {}
- WpaMsg(const QString &_msg, int _priority = 2)
- : msg(_msg), priority(_priority)
- {
- timestamp = QDateTime::currentDateTime();
- }
-
- QString getMsg() const { return msg; }
- int getPriority() const { return priority; }
- QDateTime getTimestamp() const { return timestamp; }
-
-private:
- QString msg;
- int priority;
- QDateTime timestamp;
-};
-
-#endif /* WPAMSG_H */
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index 67465aa..9b568f0 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -2,14 +2,8 @@
* WPA Supplicant - ASCII passphrase to WPA PSK tool
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -58,7 +52,7 @@ int main(int argc, char *argv[])
return 1;
}
- pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32);
+ pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
printf("network={\n");
printf("\tssid=\"%s\"\n", ssid);
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index c8854da..5426177 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -2,14 +2,8 @@
* WPA Supplicant / privileged helper program
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -558,8 +552,6 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
}
-extern struct wpa_driver_ops *wpa_drivers[];
-
static struct wpa_priv_interface *
wpa_priv_interface_init(const char *dir, const char *params)
{
@@ -579,13 +571,11 @@ wpa_priv_interface_init(const char *dir, const char *params)
iface->fd = -1;
len = pos - params;
- iface->driver_name = os_malloc(len + 1);
+ iface->driver_name = dup_binstr(params, len);
if (iface->driver_name == NULL) {
wpa_priv_interface_deinit(iface);
return NULL;
}
- os_memcpy(iface->driver_name, params, len);
- iface->driver_name[len] = '\0';
for (i = 0; wpa_drivers[i]; i++) {
if (os_strcmp(iface->driver_name,
@@ -649,7 +639,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
}
if (bind(iface->fd, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("wpa-priv-iface-init: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -954,8 +944,6 @@ static void usage(void)
}
-extern int wpa_debug_level;
-
int main(int argc, char *argv[])
{
int c, i;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 28a89af..455b158 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This file implements functions for registering and unregistering
* %wpa_supplicant interfaces. In addition, this file contains number of
@@ -23,10 +17,12 @@
#include "crypto/sha1.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
#include "eap_server/eap_methods.h"
#include "rsn_supp/wpa.h"
#include "eloop.h"
#include "config.h"
+#include "utils/ext_password.h"
#include "l2_packet/l2_packet.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -46,22 +42,23 @@
#include "gas_query.h"
#include "ap.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bgscan.h"
+#include "autoscan.h"
#include "bss.h"
#include "scan.h"
#include "offchannel.h"
+#include "hs20_supplicant.h"
+#include "wnm_sta.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n"
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n"
#ifdef EAP_TLS_OPENSSL
"\nThis product includes software developed by the OpenSSL Project\n"
"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
@@ -71,22 +68,9 @@ const char *wpa_supplicant_license =
#ifndef CONFIG_NO_STDOUT_DEBUG
/* Long text divided into parts in order to fit in C89 strings size limits. */
const char *wpa_supplicant_full_license1 =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
-"GNU General Public License for more details.\n"
-"\n";
+"";
const char *wpa_supplicant_full_license2 =
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license.\n"
+"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"
@@ -120,11 +104,6 @@ const char *wpa_supplicant_full_license5 =
"\n";
#endif /* CONFIG_NO_STDOUT_DEBUG */
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-extern struct wpa_driver_ops *wpa_drivers[];
-
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -144,8 +123,8 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
-static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
u8 key[32];
size_t keylen;
@@ -173,6 +152,11 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
keylen = 16;
alg = WPA_ALG_CCMP;
break;
+ case WPA_CIPHER_GCMP:
+ os_memcpy(key, ssid->psk, 16);
+ keylen = 16;
+ alg = WPA_ALG_GCMP;
+ break;
case WPA_CIPHER_TKIP:
/* WPA-None uses the same Michael MIC key for both TX and RX */
os_memcpy(key, ssid->psk, 16 + 8);
@@ -203,7 +187,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
MAC2STR(bssid));
wpa_blacklist_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
/*
@@ -226,7 +210,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec)
{
- if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+ if (wpa_s->conf->ap_scan == 0 &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
return;
@@ -302,16 +286,16 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
EAPOL_REQUIRE_KEY_BROADCAST;
}
- if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
eapol_conf.required_keys = 0;
}
- if (wpa_s->conf)
- eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
eapol_conf.eap_disabled =
!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+ eapol_conf.external_sim = wpa_s->conf->external_sim;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
#endif /* IEEE8021X_EAPOL */
}
@@ -389,6 +373,7 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
bgscan_deinit(wpa_s);
+ autoscan_deinit(wpa_s);
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
@@ -400,21 +385,18 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->l2_br = NULL;
}
- if (wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
- }
if (wpa_s->conf != NULL) {
struct wpa_ssid *ssid;
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
wpas_notify_network_removed(wpa_s, ssid);
- wpa_config_free(wpa_s->conf);
- wpa_s->conf = NULL;
}
os_free(wpa_s->confname);
wpa_s->confname = NULL;
+ os_free(wpa_s->confanother);
+ wpa_s->confanother = NULL;
+
wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
@@ -432,6 +414,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_bss_deinit(wpa_s);
+ wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_cancel_auth_timeout(wpa_s);
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
@@ -469,10 +452,37 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = NULL;
+
gas_query_deinit(wpa_s->gas);
wpa_s->gas = NULL;
free_hw_features(wpa_s);
+
+ os_free(wpa_s->bssid_filter);
+ wpa_s->bssid_filter = NULL;
+
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = NULL;
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = NULL;
+
+ wnm_bss_keep_alive_deinit(wpa_s);
+#ifdef CONFIG_WNM
+ wnm_deallocate_memory(wpa_s);
+#endif /* CONFIG_WNM */
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+
+ wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = NULL;
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = NULL;
+
+ os_free(wpa_s->last_scan_res);
+ wpa_s->last_scan_res = NULL;
}
@@ -486,29 +496,23 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- if (wpa_s->keys_cleared) {
- /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
- * timing issues with keys being cleared just before new keys
- * are set or just after association or something similar. This
- * shows up in group key handshake failing often because of the
- * client not receiving the first encrypted packets correctly.
- * Skipping some of the extra key clearing steps seems to help
- * in completing group key handshake more reliably. */
- wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
- "skip key clearing");
- return;
- }
+ int i, max;
- /* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
#ifdef CONFIG_IEEE80211W
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+ max = 6;
+#else /* CONFIG_IEEE80211W */
+ max = 4;
#endif /* CONFIG_IEEE80211W */
- if (addr) {
+
+ /* MLME-DELETEKEYS.request */
+ for (i = 0; i < max; i++) {
+ if (wpa_s->keys_cleared & BIT(i))
+ continue;
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+ NULL, 0);
+ }
+ if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ !is_zero_ether_addr(addr)) {
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
0);
/* MLME-SETPROTECTION.request(None) */
@@ -517,7 +521,7 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
}
- wpa_s->keys_cleared = 1;
+ wpa_s->keys_cleared = (u32) -1;
}
@@ -559,14 +563,22 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
{
+ const char *name;
+
+ if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
+ name = wpa_s->current_ssid->bgscan;
+ else
+ name = wpa_s->conf->bgscan;
+ if (name == NULL)
+ return;
if (wpas_driver_bss_selection(wpa_s))
return;
if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
return;
bgscan_deinit(wpa_s);
- if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
- if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+ if (wpa_s->current_ssid) {
+ if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
"bgscan");
/*
@@ -574,8 +586,16 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
* optimization, so the initial connection is not
* affected.
*/
- } else
+ } else {
+ struct wpa_scan_results *scan_res;
wpa_s->bgscan_ssid = wpa_s->current_ssid;
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
+ 0);
+ if (scan_res) {
+ bgscan_notify_scan(wpa_s, scan_res);
+ wpa_scan_results_free(scan_res);
+ }
+ }
} else
wpa_s->bgscan_ssid = NULL;
}
@@ -592,6 +612,29 @@ static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_BGSCAN */
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+ if (autoscan_init(wpa_s, 0))
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+ autoscan_deinit(wpa_s);
+}
+
+
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+ wpa_s->wpa_state == WPA_SCANNING) {
+ autoscan_deinit(wpa_s);
+ wpa_supplicant_start_autoscan(wpa_s);
+ }
+}
+
+
/**
* wpa_supplicant_set_state - Set current connection state
* @wpa_s: Pointer to wpa_supplicant data
@@ -609,29 +652,40 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
+ if (state == WPA_INTERFACE_DISABLED) {
+ /* Assure normal scan when interface is restored */
+ wpa_s->normal_scans = 0;
+ }
+
+ if (state == WPA_COMPLETED)
+ wpas_connect_work_done(wpa_s);
+
if (state != WPA_SCANNING)
wpa_supplicant_notify_scanning(wpa_s, 0);
if (state == WPA_COMPLETED && wpa_s->new_connection) {
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct wpa_ssid *ssid = wpa_s->current_ssid;
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed %s [id=%d id_str=%s]",
- MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
- "(reauth)" : "(auth)",
+ MACSTR " completed [id=%d id_str=%s]",
+ MAC2STR(wpa_s->bssid),
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+ wpa_s->extra_blacklist_count = 0;
wpa_s->new_connection = 0;
- wpa_s->reassociated_connection = 1;
wpa_drv_set_operstate(wpa_s, 1);
#ifndef IEEE8021X_EAPOL
wpa_drv_set_supp_port(wpa_s, 1);
#endif /* IEEE8021X_EAPOL */
wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
#ifdef CONFIG_P2P
wpas_p2p_completed(wpa_s);
#endif /* CONFIG_P2P */
+
+ sme_sched_obss_scan(wpa_s, 1);
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -639,16 +693,23 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
#ifndef IEEE8021X_EAPOL
wpa_drv_set_supp_port(wpa_s, 0);
#endif /* IEEE8021X_EAPOL */
+ sme_sched_obss_scan(wpa_s, 0);
}
wpa_s->wpa_state = state;
#ifdef CONFIG_BGSCAN
if (state == WPA_COMPLETED)
wpa_supplicant_start_bgscan(wpa_s);
- else
+ else if (state < WPA_ASSOCIATED)
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
+ if (state == WPA_AUTHENTICATING)
+ wpa_supplicant_stop_autoscan(wpa_s);
+
+ if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ wpa_supplicant_start_autoscan(wpa_s);
+
if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -665,9 +726,15 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global)
#ifdef CONFIG_WPS
struct wpa_supplicant *wpa_s = global->ifaces;
while (wpa_s) {
+ struct wpa_supplicant *next = wpa_s->next;
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
+ (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
+ wpas_p2p_disconnect(wpa_s);
+#endif /* CONFIG_P2P */
if (wpas_wps_terminate_pending(wpa_s) == 1)
pending = 1;
- wpa_s = wpa_s->next;
+ wpa_s = next;
}
#endif /* CONFIG_WPS */
if (pending)
@@ -679,11 +746,6 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global)
static void wpa_supplicant_terminate(int sig, void *signal_ctx)
{
struct wpa_global *global = signal_ctx;
- struct wpa_supplicant *wpa_s;
- for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
- "received", sig);
- }
wpa_supplicant_terminate_proc(global);
}
@@ -697,7 +759,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
if (wpa_s->wpa_state != old_state)
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -723,12 +785,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
if (wpa_s->confname == NULL)
return -1;
- conf = wpa_config_read(wpa_s->confname);
+ conf = wpa_config_read(wpa_s->confname, NULL);
if (conf == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
"file '%s' - exiting", wpa_s->confname);
return -1;
}
+ wpa_config_read(wpa_s->confanother, conf);
+
conf->changed_parameters = (unsigned int) -1;
reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
@@ -776,7 +840,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
wpa_supplicant_update_config(wpa_s);
wpa_supplicant_clear_status(wpa_s);
- if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ if (wpa_supplicant_enabled_networks(wpa_s)) {
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -799,52 +863,6 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
}
-enum wpa_cipher cipher_suite2driver(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_NONE:
- return CIPHER_NONE;
- case WPA_CIPHER_WEP40:
- return CIPHER_WEP40;
- case WPA_CIPHER_WEP104:
- return CIPHER_WEP104;
- case WPA_CIPHER_CCMP:
- return CIPHER_CCMP;
- case WPA_CIPHER_TKIP:
- default:
- return CIPHER_TKIP;
- }
-}
-
-
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
-{
- switch (key_mgmt) {
- case WPA_KEY_MGMT_NONE:
- return KEY_MGMT_NONE;
- case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
- return KEY_MGMT_802_1X_NO_WPA;
- case WPA_KEY_MGMT_IEEE8021X:
- return KEY_MGMT_802_1X;
- case WPA_KEY_MGMT_WPA_NONE:
- return KEY_MGMT_WPA_NONE;
- case WPA_KEY_MGMT_FT_IEEE8021X:
- return KEY_MGMT_FT_802_1X;
- case WPA_KEY_MGMT_FT_PSK:
- return KEY_MGMT_FT_PSK;
- case WPA_KEY_MGMT_IEEE8021X_SHA256:
- return KEY_MGMT_802_1X_SHA256;
- case WPA_KEY_MGMT_PSK_SHA256:
- return KEY_MGMT_PSK_SHA256;
- case WPA_KEY_MGMT_WPS:
- return KEY_MGMT_WPS;
- case WPA_KEY_MGMT_PSK:
- default:
- return KEY_MGMT_PSK;
- }
-}
-
-
static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct wpa_ie_data *ie)
@@ -881,7 +899,9 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
- ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) ==
+ MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
"that does not support management frame protection - "
"reject");
@@ -983,41 +1003,30 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
sel = ie.group_cipher & ssid->group_cipher;
- if (sel & WPA_CIPHER_CCMP) {
- wpa_s->group_cipher = WPA_CIPHER_CCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
- } else if (sel & WPA_CIPHER_TKIP) {
- wpa_s->group_cipher = WPA_CIPHER_TKIP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
- } else if (sel & WPA_CIPHER_WEP104) {
- wpa_s->group_cipher = WPA_CIPHER_WEP104;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
- } else if (sel & WPA_CIPHER_WEP40) {
- wpa_s->group_cipher = WPA_CIPHER_WEP40;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
- } else {
+ wpa_s->group_cipher = wpa_pick_group_cipher(sel);
+ if (wpa_s->group_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
"cipher");
return -1;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
+ wpa_cipher_txt(wpa_s->group_cipher));
sel = ie.pairwise_cipher & ssid->pairwise_cipher;
- if (sel & WPA_CIPHER_CCMP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
- } else if (sel & WPA_CIPHER_TKIP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
- } else if (sel & WPA_CIPHER_NONE) {
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
- } else {
+ wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
+ if (wpa_s->pairwise_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
"cipher");
return -1;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
+ wpa_cipher_txt(wpa_s->pairwise_cipher));
sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+ sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
if (0) {
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
@@ -1027,6 +1036,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ } else if (sel & WPA_KEY_MGMT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+ } else if (sel & WPA_KEY_MGMT_FT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1059,7 +1076,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
sel = ie.mgmt_group_cipher;
- if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+ if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1072,7 +1090,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w));
#endif /* CONFIG_IEEE80211W */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1080,21 +1100,76 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
- if (ssid->key_mgmt &
- (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
- {
+ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
#ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase) {
u8 psk[PMK_LEN];
- pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
- bss->ssid_len, 4096, psk, PMK_LEN);
+ pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
}
#endif /* CONFIG_NO_PBKDF2 */
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+ ssid->ext_psk);
+ char pw_str[64 + 1];
+ u8 psk[PMK_LEN];
+
+ if (pw == NULL) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
+ "found from external storage");
+ return -1;
+ }
+
+ if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
+ "PSK length %d in external storage",
+ (int) wpabuf_len(pw));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+ pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+ if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+ {
+ pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN);
+ os_memset(pw_str, 0, sizeof(pw_str));
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
+ "external passphrase)",
+ psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ } else
+#endif /* CONFIG_NO_PBKDF2 */
+ if (wpabuf_len(pw) == 2 * PMK_LEN) {
+ if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
+ "Invalid PSK hex string");
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
+ "PSK available");
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ }
+#endif /* CONFIG_EXT_PASSWORD */
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -1102,6 +1177,138 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
+{
+ *pos = 0x00;
+
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+#endif /* CONFIG_INTERWORKING */
+ break;
+ case 4: /* Bits 32-39 */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING)
+ *pos |= 0x01; /* Bit 32 - QoS Map */
+#endif /* CONFIG_INTERWORKING */
+ break;
+ case 5: /* Bits 40-47 */
+ break;
+ case 6: /* Bits 48-55 */
+ break;
+ }
+}
+
+
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+ u8 *pos = buf;
+ u8 len = 4, i;
+
+ if (len < wpa_s->extended_capa_len)
+ len = wpa_s->extended_capa_len;
+
+ *pos++ = WLAN_EID_EXT_CAPAB;
+ *pos++ = len;
+ for (i = 0; i < len; i++, pos++) {
+ wpas_ext_capab_byte(wpa_s, pos, i);
+
+ if (i < wpa_s->extended_capa_len) {
+ *pos &= ~wpa_s->extended_capa_mask[i];
+ *pos |= wpa_s->extended_capa[i];
+ }
+ }
+
+ while (len > 0 && buf[1 + len] == 0) {
+ len--;
+ buf[1] = len;
+ }
+ if (len == 0)
+ return 0;
+
+ return 2 + len;
+}
+
+
+static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *test_bss)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (bss == test_bss)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *test_ssid)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == test_ssid)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
+ struct wpa_ssid *test_ssid)
+{
+ if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
+ return 0;
+
+ return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
+}
+
+
+void wpas_connect_work_free(struct wpa_connect_work *cwork)
+{
+ if (cwork == NULL)
+ return;
+ os_free(cwork);
+}
+
+
+void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_connect_work *cwork;
+ struct wpa_radio_work *work = wpa_s->connect_work;
+
+ if (!work)
+ return;
+
+ wpa_s->connect_work = NULL;
+ cwork = work->ctx;
+ work->ctx = NULL;
+ wpas_connect_work_free(cwork);
+ radio_work_done(work);
+}
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
+
/**
* wpa_supplicant_associate - Request association
* @wpa_s: Pointer to wpa_supplicant data
@@ -1113,16 +1320,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
- u8 wpa_ie[200];
- size_t wpa_ie_len;
- int use_crypt, ret, i, bssid_changed;
- int algs = WPA_AUTH_ALG_OPEN;
- enum wpa_cipher cipher_pairwise, cipher_group;
- struct wpa_driver_associate_params params;
- int wep_keys_set = 0;
- struct wpa_driver_capa capa;
- int assoc_failed = 0;
- struct wpa_ssid *old_ssid;
+ struct wpa_connect_work *cwork;
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1139,6 +1337,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ wpas_p2p_ap_setup_failed(wpa_s);
return;
}
wpa_s->current_bss = bss;
@@ -1161,8 +1361,61 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
+ if (wpa_s->connect_work) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
+ return;
+ }
+
+ cwork = os_zalloc(sizeof(*cwork));
+ if (cwork == NULL)
+ return;
+
+ cwork->bss = bss;
+ cwork->ssid = ssid;
+
+ if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
+ wpas_start_assoc_cb, cwork) < 0) {
+ os_free(cwork);
+ }
+}
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_connect_work *cwork = work->ctx;
+ struct wpa_bss *bss = cwork->bss;
+ struct wpa_ssid *ssid = cwork->ssid;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ u8 wpa_ie[200];
+ size_t wpa_ie_len;
+ int use_crypt, ret, i, bssid_changed;
+ int algs = WPA_AUTH_ALG_OPEN;
+ unsigned int cipher_pairwise, cipher_group;
+ struct wpa_driver_associate_params params;
+ int wep_keys_set = 0;
+ int assoc_failed = 0;
+ struct wpa_ssid *old_ssid;
+#ifdef CONFIG_HT_OVERRIDES
+ struct ieee80211_ht_capabilities htcaps;
+ struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+
+ if (deinit) {
+ wpas_connect_work_free(cwork);
+ return;
+ }
+
+ wpa_s->connect_work = work;
+
+ if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
os_memset(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
+ wpa_s->eap_expected_failure = 0;
if (bss && !wpas_driver_bss_selection(wpa_s)) {
#ifdef CONFIG_IEEE80211R
const u8 *ie, *md = NULL;
@@ -1191,7 +1444,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
/* Use ap_scan==1 style network selection to find the network
*/
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return;
@@ -1227,17 +1480,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
- (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))) {
+ wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
- try_opportunistic = ssid->proactive_key_caching &&
+ try_opportunistic = (ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc :
+ ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
- wpa_s->current_ssid,
- try_opportunistic) == 0)
+ ssid, try_opportunistic) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -1246,11 +1496,17 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"key management and encryption suites");
return;
}
- } else if (ssid->key_mgmt &
- (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+ /*
+ * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+ * use non-WPA since the scan results did not indicate that the
+ * AP is using WPA or WPA2.
+ */
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_ie_len = 0;
+ wpa_s->wpa_proto = 0;
+ } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_ie, &wpa_ie_len)) {
@@ -1309,28 +1565,51 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"disallows" : "allows");
}
}
+
+ os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
#endif /* CONFIG_P2P */
-#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking) {
- u8 *pos = wpa_ie;
- if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
- pos += 2 + pos[1];
- os_memmove(pos + 6, pos, wpa_ie_len - (pos - wpa_ie));
- wpa_ie_len += 6;
- *pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x80; /* Bit 31 - Interworking */
+#ifdef CONFIG_HS20
+ if (is_hs20_network(wpa_s, ssid, bss)) {
+ struct wpabuf *hs20;
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ wpas_hs20_add_indication(hs20);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+ wpabuf_len(hs20));
+ wpa_ie_len += wpabuf_len(hs20);
+ wpabuf_free(hs20);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
+ /*
+ * Workaround: Add Extended Capabilities element only if the AP
+ * included this element in Beacon/Probe Response frames. Some older
+ * APs seem to have interoperability issues if this element is
+ * included, so while the standard may require us to include the
+ * element in all cases, it is justifiable to skip it to avoid
+ * interoperability issues.
+ */
+ if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
+ u8 ext_capab[10];
+ int ext_capab_len;
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
+ u8 *pos = wpa_ie;
+ if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+ pos += 2 + pos[1];
+ os_memmove(pos + ext_capab_len, pos,
+ wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
+ }
}
-#endif /* CONFIG_INTERWORKING */
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
- cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
- cipher_group = cipher_suite2driver(wpa_s->group_cipher);
+ cipher_pairwise = wpa_s->pairwise_cipher;
+ cipher_group = wpa_s->group_cipher;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
@@ -1354,7 +1633,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
/* Assume that dynamic WEP-104 keys will be used and
* set cipher suites in order for drivers to expect
* encryption. */
- cipher_pairwise = cipher_group = CIPHER_WEP104;
+ cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
}
}
#endif /* IEEE8021X_EAPOL */
@@ -1381,6 +1660,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
}
+
+ if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
+ wpa_s->conf->ap_scan == 2) {
+ params.bssid = ssid->bssid;
+ params.fixed_bssid = 1;
+ }
+
if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
params.freq == 0)
params.freq = ssid->frequency; /* Initial channel for IBSS */
@@ -1388,10 +1674,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.wpa_ie_len = wpa_ie_len;
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
- params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+ params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
params.auth_alg = algs;
params.mode = ssid->mode;
+ params.bg_scan_period = ssid->bg_scan_period;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i])
params.wep_key[i] = ssid->wep_key[i];
@@ -1400,8 +1687,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
- (params.key_mgmt_suite == KEY_MGMT_PSK ||
- params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
+ (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
if (ssid->psk_set)
params.psk = ssid->psk;
@@ -1410,8 +1697,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.drop_unencrypted = use_crypt;
#ifdef CONFIG_IEEE80211W
- params.mgmt_frame_protection = ssid->ieee80211w;
- if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
+ params.mgmt_frame_protection =
+ ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w;
+ if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data ie;
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
@@ -1432,6 +1721,33 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
else
params.uapsd = -1;
+#ifdef CONFIG_HT_OVERRIDES
+ os_memset(&htcaps, 0, sizeof(htcaps));
+ os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+ params.htcaps = (u8 *) &htcaps;
+ params.htcaps_mask = (u8 *) &htcaps_mask;
+ wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_P2P
+ /*
+ * If multi-channel concurrency is not supported, check for any
+ * frequency conflict. In case of any frequency conflict, remove the
+ * least prioritized connection.
+ */
+ if (wpa_s->num_multichan_concurrent < 2) {
+ int freq = wpa_drv_shared_freq(wpa_s);
+ if (freq > 0 && freq != params.freq) {
+ wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)",
+ freq, params.freq);
+ if (wpas_p2p_handle_frequency_conflicts(wpa_s,
+ params.freq,
+ ssid) < 0)
+ return;
+ }
+ }
+#endif /* CONFIG_P2P */
+
ret = wpa_drv_associate(wpa_s, &params);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -1484,8 +1800,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
- if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
- capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
+ if (wep_keys_set &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, ssid);
}
@@ -1513,10 +1829,8 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
struct wpa_ssid *old_ssid;
wpa_clear_keys(wpa_s, addr);
- wpa_supplicant_mark_disassoc(wpa_s);
old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = NULL;
- wpa_s->current_bss = NULL;
+ wpa_supplicant_mark_disassoc(wpa_s);
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
if (old_ssid != wpa_s->current_ssid)
@@ -1526,28 +1840,6 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
/**
- * wpa_supplicant_disassociate - Disassociate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the disassociate frame
- *
- * This function is used to request %wpa_supplicant to disassociate with the
- * current AP.
- */
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
- int reason_code)
-{
- u8 *addr = NULL;
-
- if (!is_zero_ether_addr(wpa_s->bssid)) {
- wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
- addr = wpa_s->bssid;
- }
-
- wpa_supplicant_clear_connection(wpa_s, addr);
-}
-
-
-/**
* wpa_supplicant_deauthenticate - Deauthenticate the current connection
* @wpa_s: Pointer to wpa_supplicant data
* @reason_code: IEEE 802.11 reason code for the deauthenticate frame
@@ -1559,15 +1851,66 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
+ union wpa_event_data event;
+ int zero_addr = 0;
- if (!is_zero_ether_addr(wpa_s->bssid)) {
- wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+ " pending_bssid=" MACSTR " reason=%d state=%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))
+ addr = wpa_s->pending_bssid;
+ else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+ /*
+ * When using driver-based BSS selection, we may not know the
+ * BSSID with which we are currently trying to associate. We
+ * need to notify the driver of this disconnection even in such
+ * a case, so use the all zeros address here.
+ */
addr = wpa_s->bssid;
+ zero_addr = 1;
+ }
+
+#ifdef CONFIG_TDLS
+ wpa_tdls_teardown_peers(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
+ if (addr) {
+ wpa_drv_deauthenticate(wpa_s, addr, reason_code);
+ os_memset(&event, 0, sizeof(event));
+ event.deauth_info.reason_code = (u16) reason_code;
+ event.deauth_info.locally_generated = 1;
+ wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
+ if (zero_addr)
+ addr = NULL;
}
wpa_supplicant_clear_connection(wpa_s, addr);
}
+static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (!ssid || !ssid->disabled || ssid->disabled == 2)
+ return;
+
+ ssid->disabled = 0;
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
+
+ /*
+ * Try to reassociate since there is no current configuration and a new
+ * network was made available.
+ */
+ if (!wpa_s->current_ssid && !wpa_s->disconnected)
+ wpa_s->reassociate = 1;
+}
+
/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
@@ -1579,45 +1922,21 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct wpa_ssid *other_ssid;
- int was_disabled;
-
if (ssid == NULL) {
- for (other_ssid = wpa_s->conf->ssid; other_ssid;
- other_ssid = other_ssid->next) {
- if (other_ssid->disabled == 2)
- continue; /* do not change persistent P2P group
- * data */
- if (other_ssid == wpa_s->current_ssid &&
- other_ssid->disabled)
- wpa_s->reassociate = 1;
-
- was_disabled = other_ssid->disabled;
-
- other_ssid->disabled = 0;
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ wpa_supplicant_enable_one_network(wpa_s, ssid);
+ } else
+ wpa_supplicant_enable_one_network(wpa_s, ssid);
- if (was_disabled != other_ssid->disabled)
- wpas_notify_network_enabled_changed(
- wpa_s, other_ssid);
+ if (wpa_s->reassociate && !wpa_s->disconnected) {
+ if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
+ "new network to scan filters");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
}
- if (wpa_s->reassociate)
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (ssid->disabled && ssid->disabled != 2) {
- if (wpa_s->current_ssid == NULL) {
- /*
- * Try to reassociate since there is no current
- * configuration and a new network was made available.
- */
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
- was_disabled = ssid->disabled;
- ssid->disabled = 0;
-
- if (was_disabled != ssid->disabled)
- wpas_notify_network_enabled_changed(wpa_s, ssid);
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
}
@@ -1636,6 +1955,9 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
int was_disabled;
if (ssid == NULL) {
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
for (other_ssid = wpa_s->conf->ssid; other_ssid;
other_ssid = other_ssid->next) {
was_disabled = other_ssid->disabled;
@@ -1650,19 +1972,26 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
wpa_s, other_ssid);
}
if (wpa_s->current_ssid)
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
} else if (ssid->disabled != 2) {
if (ssid == wpa_s->current_ssid)
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
was_disabled = ssid->disabled;
ssid->disabled = 1;
- if (was_disabled != ssid->disabled)
+ if (was_disabled != ssid->disabled) {
wpas_notify_network_enabled_changed(wpa_s, ssid);
+ if (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);
+ }
+ }
}
}
@@ -1680,11 +2009,14 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
int disconnected = 0;
if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
disconnected = 1;
}
+ if (ssid)
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
/*
* Mark all other networks disabled or mark all networks enabled if no
* network specified.
@@ -1696,6 +2028,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
continue; /* do not change persistent P2P group data */
other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+ if (was_disabled && !other_ssid->disabled)
+ wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
@@ -1708,10 +2042,16 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
return;
}
+ if (ssid) {
+ wpa_s->current_ssid = ssid;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ }
wpa_s->connect_without_scan = NULL;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
if (ssid)
wpas_notify_network_selected(wpa_s, ssid);
@@ -1719,6 +2059,59 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
/**
+ * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @pkcs11_engine_path: PKCS #11 engine path or NULL
+ * @pkcs11_module_path: PKCS #11 module path or NULL
+ * Returns: 0 on success; -1 on failure
+ *
+ * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
+ * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
+ * module path fails the paths will be reset to the default value (NULL).
+ */
+int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
+ const char *pkcs11_engine_path,
+ const char *pkcs11_module_path)
+{
+ char *pkcs11_engine_path_copy = NULL;
+ char *pkcs11_module_path_copy = NULL;
+
+ if (pkcs11_engine_path != NULL) {
+ pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
+ if (pkcs11_engine_path_copy == NULL)
+ return -1;
+ }
+ if (pkcs11_module_path != NULL) {
+ pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
+ if (pkcs11_module_path_copy == NULL) {
+ os_free(pkcs11_engine_path_copy);
+ return -1;
+ }
+ }
+
+ os_free(wpa_s->conf->pkcs11_engine_path);
+ os_free(wpa_s->conf->pkcs11_module_path);
+ wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
+ wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
+
+ wpa_sm_set_eapol(wpa_s->wpa, NULL);
+ eapol_sm_deinit(wpa_s->eapol);
+ wpa_s->eapol = NULL;
+ if (wpa_supplicant_init_eapol(wpa_s)) {
+ /* Error -> Reset paths to the default value (NULL) once. */
+ if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
+ wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
+ NULL);
+
+ return -1;
+ }
+ wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_set_ap_scan - Set AP scan mode for interface
* @wpa_s: wpa_supplicant structure for a network interface
* @ap_scan: AP scan mode
@@ -1800,6 +2193,29 @@ int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
/**
+ * wpa_supplicant_set_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+ int scan_interval)
+{
+ if (scan_interval < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+ scan_interval);
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+ scan_interval);
+ wpa_supplicant_update_scan_int(wpa_s, scan_interval);
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_set_debug_params - Set global debug params
* @global: wpa_global structure
* @debug_level: debug level
@@ -1874,14 +2290,14 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
entry = wpa_s->conf->ssid;
while (entry) {
- if (!entry->disabled &&
+ if (!wpas_network_disabled(wpa_s, entry) &&
((ssid_len == entry->ssid_len &&
os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
(!entry->bssid_set ||
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
#ifdef CONFIG_WPS
- if (!entry->disabled &&
+ if (!wpas_network_disabled(wpa_s, entry) &&
(entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
(entry->ssid == NULL || entry->ssid_len == 0) &&
(!entry->bssid_set ||
@@ -1889,7 +2305,7 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
return entry;
#endif /* CONFIG_WPS */
- if (!entry->disabled && entry->bssid_set &&
+ if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
entry->ssid_len == 0 &&
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
return entry;
@@ -1989,27 +2405,51 @@ 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);
- if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+#ifdef CONFIG_PEERKEY
+ if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
+ wpa_s->current_ssid->peerkey &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
+ return;
+ }
+#endif /* CONFIG_PEERKEY */
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+ (wpa_s->last_eapol_matches_bssid &&
+#ifdef CONFIG_AP
+ !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+ os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
/*
* There is possible race condition between receiving the
* association event and the EAPOL frame since they are coming
* through different paths from the driver. In order to avoid
* issues in trying to process the EAPOL frame before receiving
* association information, lets queue it for processing until
- * the association event is received.
+ * the association event is received. This may also be needed in
+ * driver-based roaming case, so also use src_addr != BSSID as a
+ * trigger if we have previously confirmed that the
+ * Authenticator uses BSSID as the src_addr (which is not the
+ * case with wired IEEE 802.1X).
*/
wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
- "of received EAPOL frame");
+ "of received EAPOL frame (state=%s bssid=" MACSTR ")",
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ MAC2STR(wpa_s->bssid));
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
- os_get_time(&wpa_s->pending_eapol_rx_time);
+ os_get_reltime(&wpa_s->pending_eapol_rx_time);
os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
ETH_ALEN);
}
return;
}
+ wpa_s->last_eapol_matches_bssid =
+ os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
+
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
@@ -2084,7 +2524,10 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
- } else if (!(wpa_s->drv_flags &
+ } else if ((!wpa_s->p2p_mgmt ||
+ !(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+ !(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
@@ -2104,14 +2547,35 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
return -1;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
- MAC2STR(wpa_s->own_addr));
- wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
return 0;
}
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct l2_ethhdr *eth;
+
+ if (len < sizeof(*eth))
+ return;
+ eth = (const struct l2_ethhdr *) buf;
+
+ if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+ !(eth->h_dest[0] & 0x01)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+ " (bridge - not for this interface - ignore)",
+ MAC2STR(src_addr), MAC2STR(eth->h_dest));
+ return;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+ " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+ wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+ len - sizeof(*eth));
+}
+
+
/**
* wpa_supplicant_driver_init - Initialize driver interface parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -2128,14 +2592,18 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
return -1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+ MAC2STR(wpa_s->own_addr));
+ wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
if (wpa_s->bridge_ifname[0]) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
wpa_s->own_addr,
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s,
- 0);
+ wpa_supplicant_rx_eapol_bridge,
+ wpa_s, 1);
if (wpa_s->l2_br == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
"connection for the bridge interface '%s'",
@@ -2154,7 +2622,13 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
wpa_drv_flush_pmkid(wpa_s);
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
- if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ wpa_s->prev_scan_wildcard = 0;
+
+ if (wpa_supplicant_enabled_networks(wpa_s)) {
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ interface_count = 0;
+ }
if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
100000))
wpa_supplicant_req_scan(wpa_s, interface_count,
@@ -2181,7 +2655,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
wpa_s = os_zalloc(sizeof(*wpa_s));
if (wpa_s == NULL)
return NULL;
- wpa_s->scan_req = 1;
+ wpa_s->scan_req = INITIAL_SCAN_REQ;
wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
wpa_s->parent = wpa_s;
@@ -2191,10 +2665,609 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
}
+#ifdef CONFIG_HT_OVERRIDES
+
+static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ const char *ht_mcs)
+{
+ /* parse ht_mcs into hex array */
+ int i;
+ const char *tmp = ht_mcs;
+ char *end = NULL;
+
+ /* If ht_mcs is null, do not set anything */
+ if (!ht_mcs)
+ return 0;
+
+ /* This is what we are setting in the kernel */
+ os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ errno = 0;
+ long v = strtol(tmp, &end, 16);
+ if (errno == 0) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "htcap value[%i]: %ld end: %p tmp: %p",
+ i, v, end, tmp);
+ if (end == tmp)
+ break;
+
+ htcaps->supported_mcs_set[i] = v;
+ tmp = end;
+ } else {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to parse ht-mcs: %s, error: %s\n",
+ ht_mcs, strerror(errno));
+ return -1;
+ }
+ }
+
+ /*
+ * If we were able to parse any values, then set mask for the MCS set.
+ */
+ if (i) {
+ os_memset(&htcaps_mask->supported_mcs_set, 0xff,
+ IEEE80211_HT_MCS_MASK_LEN - 1);
+ /* skip the 3 reserved bits */
+ htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
+ 0x1f;
+ }
+
+ return 0;
+}
+
+
+static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ u16 msk;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
+ if (disabled == -1)
+ return 0;
+
+ msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
+ htcaps_mask->ht_capabilities_info |= msk;
+ if (disabled)
+ htcaps->ht_capabilities_info &= msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
+static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int factor)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
+ if (factor == -1)
+ return 0;
+
+ if (factor < 0 || factor > 3) {
+ wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
+ "Must be 0-3 or -1", factor);
+ return -EINVAL;
+ }
+
+ htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
+ htcaps->a_mpdu_params &= ~0x3;
+ htcaps->a_mpdu_params |= factor & 0x3;
+
+ return 0;
+}
+
+
+static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int density)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
+ if (density == -1)
+ return 0;
+
+ if (density < 0 || density > 7) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "ampdu_density: %d out of range. Must be 0-7 or -1.",
+ density);
+ return -EINVAL;
+ }
+
+ htcaps_mask->a_mpdu_params |= 0x1C;
+ htcaps->a_mpdu_params &= ~(0x1C);
+ htcaps->a_mpdu_params |= (density << 2) & 0x1C;
+
+ return 0;
+}
+
+
+static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* Masking these out disables HT40 */
+ u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
+static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* Masking these out disables SGI */
+ u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
+void wpa_supplicant_apply_ht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ struct ieee80211_ht_capabilities *htcaps;
+ struct ieee80211_ht_capabilities *htcaps_mask;
+
+ if (!ssid)
+ return;
+
+ params->disable_ht = ssid->disable_ht;
+ if (!params->htcaps || !params->htcaps_mask)
+ return;
+
+ htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
+ htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
+ wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
+ wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
+ ssid->disable_max_amsdu);
+ wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
+ wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
+ wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
+ wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
+}
+
+#endif /* CONFIG_HT_OVERRIDES */
+
+
+#ifdef CONFIG_VHT_OVERRIDES
+void wpa_supplicant_apply_vht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ struct ieee80211_vht_capabilities *vhtcaps;
+ struct ieee80211_vht_capabilities *vhtcaps_mask;
+
+ if (!ssid)
+ return;
+
+ params->disable_vht = ssid->disable_vht;
+
+ vhtcaps = (void *) params->vhtcaps;
+ vhtcaps_mask = (void *) params->vhtcaps_mask;
+
+ if (!vhtcaps || !vhtcaps_mask)
+ return;
+
+ vhtcaps->vht_capabilities_info = ssid->vht_capa;
+ vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+
+#define OVERRIDE_MCS(i) \
+ if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
+ vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
+ 3 << 2 * (i - 1); \
+ vhtcaps->vht_supported_mcs_set.tx_map |= \
+ 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); \
+ vhtcaps->vht_supported_mcs_set.rx_map |= \
+ ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \
+ }
+
+ OVERRIDE_MCS(1);
+ OVERRIDE_MCS(2);
+ OVERRIDE_MCS(3);
+ OVERRIDE_MCS(4);
+ OVERRIDE_MCS(5);
+ OVERRIDE_MCS(6);
+ OVERRIDE_MCS(7);
+ OVERRIDE_MCS(8);
+}
+#endif /* CONFIG_VHT_OVERRIDES */
+
+
+static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+ size_t len;
+
+ if (!wpa_s->conf->pcsc_reader)
+ return 0;
+
+ wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
+ if (!wpa_s->scard)
+ return 1;
+
+ if (wpa_s->conf->pcsc_pin &&
+ scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+ return -1;
+ }
+
+ len = sizeof(wpa_s->imsi) - 1;
+ if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+ return -1;
+ }
+ wpa_s->imsi[len] = '\0';
+
+ wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+ wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+
+ wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+ eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+ return 0;
+}
+
+
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+ char *val, *pos;
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+ eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+ if (!wpa_s->conf->ext_password_backend)
+ return 0;
+
+ val = os_strdup(wpa_s->conf->ext_password_backend);
+ if (val == NULL)
+ return -1;
+ pos = os_strchr(val, ':');
+ if (pos)
+ *pos++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+ wpa_s->ext_pw = ext_password_init(val, pos);
+ os_free(val);
+ if (wpa_s->ext_pw == NULL) {
+ wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+ return -1;
+ }
+ eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+ return 0;
+}
+
+
+static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
+ const char *rn)
+{
+ struct wpa_supplicant *iface = wpa_s->global->ifaces;
+ struct wpa_radio *radio;
+
+ while (rn && iface) {
+ radio = iface->radio;
+ if (radio && os_strcmp(rn, radio->name) == 0) {
+ wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
+ wpa_s->ifname, rn);
+ dl_list_add(&radio->ifaces, &wpa_s->radio_list);
+ return radio;
+ }
+
+ iface = iface->next;
+ }
+
+ wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
+ wpa_s->ifname, rn ? rn : "N/A");
+ radio = os_zalloc(sizeof(*radio));
+ if (radio == NULL)
+ return NULL;
+
+ if (rn)
+ os_strlcpy(radio->name, rn, sizeof(radio->name));
+ dl_list_init(&radio->ifaces);
+ dl_list_init(&radio->work);
+ dl_list_add(&radio->ifaces, &wpa_s->radio_list);
+
+ return radio;
+}
+
+
+static void radio_work_free(struct wpa_radio_work *work)
+{
+ if (work->wpa_s->scan_work == work) {
+ /* This should not really happen. */
+ wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
+ work->type, work, work->started);
+ work->wpa_s->scan_work = NULL;
+ }
+
+#ifdef CONFIG_P2P
+ if (work->wpa_s->p2p_scan_work == work) {
+ /* This should not really happen. */
+ wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
+ work->type, work, work->started);
+ work->wpa_s->p2p_scan_work = NULL;
+ }
+#endif /* CONFIG_P2P */
+
+ dl_list_del(&work->list);
+ os_free(work);
+}
+
+
+static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_radio *radio = eloop_ctx;
+ struct wpa_radio_work *work;
+ struct os_reltime now, diff;
+ struct wpa_supplicant *wpa_s;
+
+ work = dl_list_first(&radio->work, struct wpa_radio_work, list);
+ if (work == NULL)
+ 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->external_scan_running) {
+ wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
+ return;
+ }
+
+ 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",
+ work->type, work, diff.sec, diff.usec);
+ work->started = 1;
+ work->time = now;
+ work->cb(work, 0);
+}
+
+
+void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s, const char *type)
+{
+ struct wpa_radio_work *work, *tmp;
+ struct wpa_radio *radio = wpa_s->radio;
+
+ dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
+ list) {
+ if (type && (work->started || os_strcmp(type, work->type) != 0))
+ continue;
+ if (work->started) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Leaving started radio work '%s'@%p in the list",
+ work->type, work);
+ continue;
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG, "Remove unstarted radio work '%s'@%p",
+ work->type, work);
+ work->cb(work, 1);
+ radio_work_free(work);
+ }
+}
+
+
+static void radio_remove_interface(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio *radio = wpa_s->radio;
+
+ if (!radio)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
+ wpa_s->ifname, radio->name);
+ dl_list_del(&wpa_s->radio_list);
+ if (!dl_list_empty(&radio->ifaces)) {
+ wpa_s->radio = NULL;
+ return; /* Interfaces remain for this radio */
+ }
+
+ wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
+ radio_remove_unstarted_work(wpa_s, NULL);
+ eloop_cancel_timeout(radio_start_next_work, radio, NULL);
+ wpa_s->radio = NULL;
+ os_free(radio);
+}
+
+
+void radio_work_check_next(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio *radio = wpa_s->radio;
+
+ if (dl_list_empty(&radio->work))
+ return;
+ eloop_cancel_timeout(radio_start_next_work, radio, NULL);
+ eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
+}
+
+
+/**
+ * radio_add_work - Add a radio work item
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency of the offchannel operation in MHz or 0
+ * @type: Unique identifier for each type of work
+ * @next: Force as the next work to be executed
+ * @cb: Callback function for indicating when radio is available
+ * @ctx: Context pointer for the work (work->ctx in cb())
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to request time for an operation that requires
+ * exclusive radio control. Once the radio is available, the registered callback
+ * function will be called. radio_work_done() must be called once the exclusive
+ * radio operation has been completed, so that the radio is freed for other
+ * operations. The special case of deinit=1 is used to free the context data
+ * during interface removal. That does not allow the callback function to start
+ * the radio operation, i.e., it must free any resources allocated for the radio
+ * work and return.
+ *
+ * The @freq parameter can be used to indicate a single channel on which the
+ * offchannel operation will occur. This may allow multiple radio work
+ * operations to be performed in parallel if they apply for the same channel.
+ * Setting this to 0 indicates that the work item may use multiple channels or
+ * requires exclusive control of the radio.
+ */
+int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
+ const char *type, int next,
+ void (*cb)(struct wpa_radio_work *work, int deinit),
+ void *ctx)
+{
+ struct wpa_radio_work *work;
+ int was_empty;
+
+ work = os_zalloc(sizeof(*work));
+ if (work == NULL)
+ return -1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
+ os_get_reltime(&work->time);
+ work->freq = freq;
+ work->type = type;
+ work->wpa_s = wpa_s;
+ work->cb = cb;
+ work->ctx = ctx;
+
+ was_empty = dl_list_empty(&wpa_s->radio->work);
+ if (next)
+ dl_list_add(&wpa_s->radio->work, &work->list);
+ else
+ dl_list_add_tail(&wpa_s->radio->work, &work->list);
+ 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);
+ }
+
+ return 0;
+}
+
+
+/**
+ * radio_work_done - Indicate that a radio work item has been completed
+ * @work: Completed work
+ *
+ * This function is called once the callback function registered with
+ * radio_add_work() has completed its work.
+ */
+void radio_work_done(struct wpa_radio_work *work)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct os_reltime now, diff;
+ unsigned int started = work->started;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &work->time, &diff);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
+ work->type, work, started ? "done" : "canceled",
+ diff.sec, diff.usec);
+ radio_work_free(work);
+ if (started)
+ radio_work_check_next(wpa_s);
+}
+
+
+static int wpas_init_driver(struct wpa_supplicant *wpa_s,
+ struct wpa_interface *iface)
+{
+ const char *ifname, *driver, *rn;
+
+ driver = iface->driver;
+next_driver:
+ if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+ return -1;
+
+ wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
+ if (wpa_s->drv_priv == NULL) {
+ const char *pos;
+ pos = driver ? os_strchr(driver, ',') : NULL;
+ if (pos) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+ "driver interface - try next driver wrapper");
+ driver = pos + 1;
+ goto next_driver;
+ }
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+ "interface");
+ return -1;
+ }
+ if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+ "driver_param '%s'", wpa_s->conf->driver_param);
+ return -1;
+ }
+
+ ifname = wpa_drv_get_ifname(wpa_s);
+ if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+ "interface name with '%s'", ifname);
+ os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+ }
+
+ if (wpa_s->driver->get_radio_name)
+ rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ else
+ rn = NULL;
+ if (rn && rn[0] == '\0')
+ rn = NULL;
+
+ wpa_s->radio = radio_add_interface(wpa_s, rn);
+ if (wpa_s->radio == NULL)
+ return -1;
+
+ return 0;
+}
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
- const char *ifname, *driver;
struct wpa_driver_capa capa;
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
@@ -2218,12 +3291,14 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
#else /* CONFIG_BACKEND_FILE */
wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
- wpa_s->conf = wpa_config_read(wpa_s->confname);
+ wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "Failed to read or parse "
"configuration '%s'.", wpa_s->confname);
return -1;
}
+ wpa_s->confanother = os_rel2abs_path(iface->confanother);
+ wpa_config_read(wpa_s->confanother, wpa_s->conf);
/*
* Override ctrl_interface and driver_param if set on command
@@ -2240,6 +3315,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->conf->driver_param =
os_strdup(iface->driver_param);
}
+
+ if (iface->p2p_mgmt && !iface->ctrl_interface) {
+ os_free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface = NULL;
+ }
} else
wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
iface->driver_param);
@@ -2279,37 +3359,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
* L2 receive handler so that association events are processed before
* EAPOL-Key packets if both become available for the same select()
* call. */
- driver = iface->driver;
-next_driver:
- if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
- return -1;
-
- wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
- if (wpa_s->drv_priv == NULL) {
- const char *pos;
- pos = driver ? os_strchr(driver, ',') : NULL;
- if (pos) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
- "driver interface - try next driver wrapper");
- driver = pos + 1;
- goto next_driver;
- }
- wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
- "interface");
- return -1;
- }
- if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
- wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
- "driver_param '%s'", wpa_s->conf->driver_param);
+ if (wpas_init_driver(wpa_s, iface) < 0)
return -1;
- }
-
- ifname = wpa_drv_get_ifname(wpa_s);
- if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
- "interface name with '%s'", ifname);
- os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
- }
if (wpa_supplicant_init_wpa(wpa_s) < 0)
return -1;
@@ -2350,21 +3401,44 @@ next_driver:
if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
+ wpa_s->drv_enc = capa.enc;
+ 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->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;
wpa_s->max_stations = capa.max_stations;
+ wpa_s->extended_capa = capa.extended_capa;
+ wpa_s->extended_capa_mask = capa.extended_capa_mask;
+ wpa_s->extended_capa_len = capa.extended_capa_len;
+ wpa_s->num_multichan_concurrent =
+ capa.num_multichan_concurrent;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
+ /*
+ * Only take p2p_mgmt parameters when P2P Device is supported.
+ * Doing it here as it determines whether l2_packet_init() will be done
+ * during wpa_supplicant_driver_init().
+ */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+ wpa_s->p2p_mgmt = iface->p2p_mgmt;
+ else
+ iface->p2p_mgmt = 1;
+
+ if (wpa_s->num_multichan_concurrent == 0)
+ wpa_s->num_multichan_concurrent = 1;
+
if (wpa_supplicant_driver_init(wpa_s) < 0)
return -1;
#ifdef CONFIG_TDLS
- if (wpa_tdls_init(wpa_s->wpa))
+ if ((!iface->p2p_mgmt ||
+ !(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+ wpa_tdls_init(wpa_s->wpa))
return -1;
#endif /* CONFIG_TDLS */
@@ -2402,7 +3476,7 @@ next_driver:
}
#ifdef CONFIG_P2P
- if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+ if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
return -1;
}
@@ -2411,13 +3485,35 @@ next_driver:
if (wpa_bss_init(wpa_s) < 0)
return -1;
+#ifdef CONFIG_EAP_PROXY
+{
+ size_t len;
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi,
+ &len);
+ if (wpa_s->mnc_len > 0) {
+ wpa_s->imsi[len] = '\0';
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+ } else {
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+ }
+}
+#endif /* CONFIG_EAP_PROXY */
+
+ if (pcsc_reader_init(wpa_s) < 0)
+ return -1;
+
+ if (wpas_init_ext_pw(wpa_s) < 0)
+ return -1;
+
return 0;
}
static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
- int notify)
+ int notify, int terminate)
{
+ wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
@@ -2436,11 +3532,29 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
- if (notify)
- wpas_notify_iface_removed(wpa_s);
+ wpas_ctrl_radio_work_flush(wpa_s);
+ radio_remove_interface(wpa_s);
if (wpa_s->drv_priv)
wpa_drv_deinit(wpa_s);
+
+ if (notify)
+ wpas_notify_iface_removed(wpa_s);
+
+ if (terminate)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
+
+ if (wpa_s->ctrl_iface) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
+ }
+
+ if (wpa_s->conf != NULL) {
+ wpa_config_free(wpa_s->conf);
+ wpa_s->conf = NULL;
+ }
+
+ os_free(wpa_s);
}
@@ -2490,15 +3604,13 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
iface->ifname);
- wpa_supplicant_deinit_iface(wpa_s, 0);
- os_free(wpa_s);
+ wpa_supplicant_deinit_iface(wpa_s, 0, 0);
return NULL;
}
/* Notify the control interfaces about new iface */
if (wpas_notify_iface_added(wpa_s)) {
- wpa_supplicant_deinit_iface(wpa_s, 1);
- os_free(wpa_s);
+ wpa_supplicant_deinit_iface(wpa_s, 1, 0);
return NULL;
}
@@ -2509,6 +3621,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
global->ifaces = wpa_s;
wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
return wpa_s;
}
@@ -2526,7 +3639,8 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
* %wpa_supplicant is terminated.
*/
int wpa_supplicant_remove_iface(struct wpa_global *global,
- struct wpa_supplicant *wpa_s)
+ struct wpa_supplicant *wpa_s,
+ int terminate)
{
struct wpa_supplicant *prev;
@@ -2546,8 +3660,9 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
if (global->p2p_group_formation == wpa_s)
global->p2p_group_formation = NULL;
- wpa_supplicant_deinit_iface(wpa_s, 1);
- os_free(wpa_s);
+ if (global->p2p_invite_group == wpa_s)
+ global->p2p_invite_group = NULL;
+ wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
return 0;
}
@@ -2636,6 +3751,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
wpa_debug_open_file(params->wpa_debug_file_path);
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
+ if (params->wpa_debug_tracing) {
+ ret = wpa_debug_open_linux_tracing();
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "Failed to enable trace logging");
+ return NULL;
+ }
+ }
ret = eap_register_methods();
if (ret) {
@@ -2659,6 +3782,9 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->ctrl_interface)
global->params.ctrl_interface =
os_strdup(params->ctrl_interface);
+ if (params->ctrl_interface_group)
+ global->params.ctrl_interface_group =
+ os_strdup(params->ctrl_interface_group);
if (params->override_driver)
global->params.override_driver =
os_strdup(params->override_driver);
@@ -2706,6 +3832,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
return NULL;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wifi_display_init(global) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return global;
}
@@ -2757,12 +3891,12 @@ void wpa_supplicant_deinit(struct wpa_global *global)
if (global == NULL)
return;
-#ifdef CONFIG_P2P
- wpas_p2p_deinit_global(global);
-#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
while (global->ifaces)
- wpa_supplicant_remove_iface(global, global->ifaces);
+ wpa_supplicant_remove_iface(global, global->ifaces, 1);
if (global->ctrl_iface)
wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
@@ -2790,12 +3924,18 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.pid_file);
}
os_free(global->params.ctrl_interface);
+ os_free(global->params.ctrl_interface_group);
os_free(global->params.override_driver);
os_free(global->params.override_ctrl_interface);
+ os_free(global->p2p_disallow_freq.range);
+ os_free(global->p2p_go_avoid_freq.range);
+ os_free(global->add_psk);
+
os_free(global);
wpa_debug_close_syslog();
wpa_debug_close_file();
+ wpa_debug_close_linux_tracing();
}
@@ -2813,6 +3953,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
}
}
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+ wpas_init_ext_pw(wpa_s);
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -2879,11 +4022,24 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
int count;
int *freqs = NULL;
+ wpas_connect_work_done(wpa_s);
+
/*
* Remove possible authentication timeout since the connection failed.
*/
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+ if (wpa_s->disconnected) {
+ /*
+ * There is no point in blacklisting the AP if this event is
+ * generated based on local request to disconnect.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
+ "indication since interface has been put into "
+ "disconnected state");
+ return;
+ }
+
/*
* Add the failed BSSID into the blacklist and speed up next scan
* attempt if there could be other APs that could accept association.
@@ -2915,6 +4071,18 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
}
+ /*
+ * Add previous failure count in case the temporary blacklist was
+ * cleared due to no other BSSes being available.
+ */
+ count += wpa_s->extra_blacklist_count;
+
+ if (count > 3 && wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG, "Continuous association failures - "
+ "consider temporary network disabling");
+ wpas_auth_failed(wpa_s);
+ }
+
switch (count) {
case 1:
timeout = 100;
@@ -2925,10 +4093,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
case 3:
timeout = 1000;
break;
- default:
+ case 4:
timeout = 5000;
+ break;
+ default:
+ timeout = 10000;
+ break;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
+ "ms", count, timeout);
+
/*
* TODO: if more than one possible AP is available in scan results,
* could try the other ones before requesting a new scan.
@@ -3005,6 +4180,10 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
break;
+ case WPA_CTRL_REQ_SIM:
+ os_free(eap->external_sim_resp);
+ eap->external_sim_resp = os_strdup(value);
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
@@ -3017,3 +4196,256 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
#endif /* IEEE8021X_EAPOL */
}
#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ int i;
+ unsigned int drv_enc;
+
+ if (ssid == NULL)
+ return 1;
+
+ if (ssid->disabled)
+ return 1;
+
+ if (wpa_s && wpa_s->drv_capa_known)
+ drv_enc = wpa_s->drv_enc;
+ else
+ drv_enc = (unsigned int) -1;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ size_t len = ssid->wep_key_len[i];
+ if (len == 0)
+ continue;
+ if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+ continue;
+ if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+ continue;
+ if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+ continue;
+ return 1; /* invalid WEP key */
+ }
+
+ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+ !ssid->ext_psk)
+ return 1;
+
+ return 0;
+}
+
+
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
+ return 1;
+ if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
+ return 0;
+ return -1;
+}
+
+
+void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int dur;
+ struct os_reltime now;
+
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "Authentication failure but no known "
+ "SSID block");
+ return;
+ }
+
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ return;
+
+ ssid->auth_failures++;
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) {
+ /*
+ * Skip the wait time since there is a short timeout on the
+ * connection to a P2P group.
+ */
+ return;
+ }
+#endif /* CONFIG_P2P */
+
+ if (ssid->auth_failures > 50)
+ dur = 300;
+ else if (ssid->auth_failures > 20)
+ dur = 120;
+ else if (ssid->auth_failures > 10)
+ dur = 60;
+ else if (ssid->auth_failures > 5)
+ dur = 30;
+ else if (ssid->auth_failures > 1)
+ dur = 20;
+ else
+ dur = 10;
+
+ os_get_reltime(&now);
+ if (now.sec + dur <= ssid->disabled_until.sec)
+ return;
+
+ ssid->disabled_until.sec = now.sec + dur;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
+ "id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+ ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->auth_failures, dur);
+}
+
+
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int clear_failures)
+{
+ if (ssid == NULL)
+ return;
+
+ if (ssid->disabled_until.sec) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
+ "id=%d ssid=\"%s\"",
+ ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ }
+ ssid->disabled_until.sec = 0;
+ ssid->disabled_until.usec = 0;
+ if (clear_failures)
+ ssid->auth_failures = 0;
+}
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->disallow_aps_bssid == NULL)
+ return 0;
+
+ for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+ if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+ bssid, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+ size_t ssid_len)
+{
+ size_t i;
+
+ if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+ return 0;
+
+ for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+ struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+ if (ssid_len == s->ssid_len &&
+ os_memcmp(ssid, s->ssid, ssid_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpas_request_connection - Request a new connection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request a new connection to be found. It will mark
+ * the interface to allow reassociation and request a new scan to find a
+ * suitable network to connect to.
+ */
+void wpas_request_connection(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ wpa_s->extra_blacklist_count = 0;
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+ int *freq_array, unsigned int len)
+{
+ unsigned int i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
+ len, title);
+ for (i = 0; i < len; i++)
+ wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]);
+}
+
+
+/*
+ * Find the operating frequencies of any of the virtual interfaces that
+ * are using the same radio as the current interface.
+ */
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+ int *freq_array, unsigned int len)
+{
+ struct wpa_supplicant *ifs;
+ u8 bssid[ETH_ALEN];
+ int freq;
+ unsigned int idx = 0, i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Determining shared radio frequencies (max len %u)", len);
+ os_memset(freq_array, 0, sizeof(int) * len);
+
+ /* First add the frequency of the local interface */
+ if (wpa_s->current_ssid != NULL && wpa_s->assoc_freq != 0) {
+ if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)
+ freq_array[idx++] = wpa_s->current_ssid->frequency;
+ else if (wpa_drv_get_bssid(wpa_s, bssid) == 0)
+ freq_array[idx++] = wpa_s->assoc_freq;
+ }
+
+ /* If get_radio_name is not supported, use only the local freq */
+ if (!wpa_s->driver->get_radio_name) {
+ freq = wpa_drv_shared_freq(wpa_s);
+ if (freq > 0 && idx < len &&
+ (idx == 0 || freq_array[0] != freq))
+ freq_array[idx++] = freq;
+ dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx);
+ return idx;
+ }
+
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (wpa_s == ifs)
+ continue;
+
+ if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+ continue;
+
+ if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+ ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+ freq = ifs->current_ssid->frequency;
+ else if (wpa_drv_get_bssid(ifs, bssid) == 0)
+ freq = ifs->assoc_freq;
+ else
+ continue;
+
+ /* Hold only distinct freqs */
+ for (i = 0; i < idx; i++)
+ if (freq_array[i] == freq)
+ break;
+
+ if (i == idx)
+ freq_array[idx++] = freq;
+ }
+
+ dump_freq_array(wpa_s, "completed iteration", freq_array, idx);
+ return idx;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d393015..9d3bf6d 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -214,6 +214,22 @@ fast_reauth=1
# to external program(s)
#wps_cred_processing=0
+# Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing
+# The vendor attribute contents to be added in M1 (hex string)
+#wps_vendor_ext_m1=000137100100020001
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# station. This can be generated, e.g., with nfc_pw_token. When these
+# parameters are used, the station is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
# Maximum number of BSS entries to keep in memory
# Default: 200
# This can be used to limit memory use on the BSS entries (cached scan
@@ -221,12 +237,83 @@ fast_reauth=1
# of APs when using ap_scan=1 mode.
#bss_max_count=200
+# Automatic scan
+# This is an optional set of parameters for automatic scanning
+# within an interface in following format:
+#autoscan=<autoscan module name>:<module parameters>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
+#autoscan=exponential:3:300
+# Which means a delay between scans on a base exponential of 3,
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
+#autoscan=periodic:30
+# So a delay of 30 seconds will be applied between each scan
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
# 1 = only include configured SSIDs in scan results/BSS table
#filter_ssids=0
+# Password (and passphrase, etc.) backend for external storage
+# format: <backend name>[:<optional backend parameters>]
+#ext_password_backend=test:pw1=password|pw2=testing
+
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in P2P GO mode to clean up
+# inactive stations.
+#p2p_go_max_inactivity=300
+
+# Opportunistic Key Caching (also known as Proactive Key Caching) default
+# This parameter can be used to set the default behavior for the
+# proactive_key_caching parameter. By default, OKC is disabled unless enabled
+# with the global okc=1 parameter or with the per-network
+# proactive_key_caching=1 parameter. With okc=1, OKC is enabled by default, but
+# can be disabled with per-network proactive_key_caching=0 parameter.
+#okc=0
+
+# 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.
+#pmf=0
+
+# Enabled SAE finite cyclic groups in preference order
+# By default (if this parameter is not set), the mandatory group 19 (ECC group
+# defined over a 256-bit prime order field) is preferred, but other groups are
+# also enabled. If this parameter is set, the groups will be tried in the
+# indicated order. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=21 20 19 26 25
+
+# Default value for DTIM period (if not overridden in network block)
+#dtim_period=2
+
+# Default value for Beacon interval (if not overridden in network block)
+#beacon_int=100
+
+# Additional vendor specific elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements). This is used in AP and P2P GO modes.
+#ap_vendor_elements=dd0411223301
+
+# Ignore scan results older than request
+#
+# The driver may have a cache of scan results that makes it return
+# information that is older than our scan trigger. This parameter can
+# be used to configure such old information to be ignored instead of
+# allowing it to update the internal BSS table.
+#ignore_old_scan_res=0
+
+# scan_cur_freq: Whether to scan only the current frequency
+# 0: Scan all available frequencies. (Default)
+# 1: Scan current operating frequency if another VIF on the same radio
+# is already associated.
# Interworking (IEEE 802.11u)
@@ -239,23 +326,140 @@ fast_reauth=1
# is enabled.
# hessid=00:11:22:33:44:55
-# Home Realm for Interworking
-#home_realm=example.com
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
-# Username for Interworking network selection
-#home_username=user
-
-# Password for Interworking network selection
-#home_password=secret
-
-# CA certificate for Interworking network selection
-#home_ca_cert=/etc/cert/ca.pem
-
-# IMSI in <MCC> | <MNC> | '-' | <MSIN> format
-#home_imsi=232010000000000
-
-# Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> format
-#home_milenage=90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# temporary: Whether this credential is temporary and not to be saved
+#
+# priority: Priority group
+# By default, all networks and credentials get the same priority group
+# (0). This field can be used to give higher priority for credentials
+# (and similarly in struct wpa_ssid for network blocks) to change the
+# Interworking automatic networking selection behavior. The matching
+# network (based on either an enabled network block or a credential)
+# with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+# This field is used with Interworking networking selection for a case
+# where client certificate/private key is used for authentication
+# (EAP-TLS). Full path to the file should be used since working
+# directory may change when wpa_supplicant is run in the background.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key: File path to client private key file (PEM/DER/PFX)
+# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+# commented out. Both the private key and certificate will be read
+# from the PKCS#12 file in this case. Full path to the file should be
+# used since working directory may change when wpa_supplicant is run
+# in the background.
+#
+# Windows certificate store can be used by leaving client_cert out and
+# configuring private_key in one of the following formats:
+#
+# cert://substring_to_match
+#
+# hash://certificate_thumbprint_in_hex
+#
+# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#
+# Note that when running wpa_supplicant as an application, the user
+# certificate store (My user account) is used, whereas computer store
+# (Computer account) is used when running wpasvc as a service.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+# format
+#
+# domain: Home service provider FQDN(s)
+# This is used to compare against the Domain Name List to figure out
+# whether the AP is operated by the Home SP. Multiple domain entries can
+# be used to configure alternative FQDNs that will be considered home
+# networks.
+#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# excluded_ssid: Excluded SSID
+# This optional field can be used to excluded specific SSID(s) from
+# matching with the network. Multiple entries can be used to specify more
+# than one SSID.
+#
+# for example:
+#
+#cred={
+# realm="example.com"
+# username="user@example.com"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+#}
+#
+#cred={
+# imsi="310026-000000000"
+# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
+
+# Hotspot 2.0
+# hs20=1
# network block
#
@@ -274,8 +478,10 @@ fast_reauth=1
# to external action script through wpa_cli as WPA_ID_STR environment
# variable to make it easier to do network specific configuration.
#
-# ssid: SSID (mandatory); either as an ASCII string with double quotation or
-# as hex string; network name
+# ssid: SSID (mandatory); network name in one of the optional formats:
+# - an ASCII string with double quotation
+# - a hex string (two characters per octet of SSID)
+# - a printf-escaped ASCII string P"<escaped string>"
#
# scan_ssid:
# 0 = do not scan this SSID with specific Probe Request frames (default)
@@ -302,9 +508,10 @@ fast_reauth=1
# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
# 1 = IBSS (ad-hoc, peer-to-peer)
# 2 = AP (access point)
-# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
-# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires
-# following network block options:
+# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) and
+# WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE (fixed group key
+# TKIP/CCMP) is available for backwards compatibility, but its use is
+# deprecated. WPA-None requires following network block options:
# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
# both), and psk must also be set.
#
@@ -326,6 +533,30 @@ fast_reauth=1
# set, scan results that do not match any of the specified frequencies are not
# considered when selecting a BSS.
#
+# This can also be set on the outside of the network block. In this case,
+# it limits the frequencies that will be scanned.
+#
+# bgscan: Background scanning
+# wpa_supplicant behavior for background scanning can be specified by
+# configuring a bgscan module. These modules are responsible for requesting
+# background scans for the purpose of roaming within an ESS (i.e., within a
+# single network block with all the APs using the same SSID). The bgscan
+# parameter uses following format: "<bgscan module name>:<module parameters>"
+# Following bgscan modules are available:
+# simple - Periodic background scans based on signal strength
+# bgscan="simple:<short bgscan interval in seconds>:<signal strength threshold>:
+# <long interval>"
+# bgscan="simple:30:-45:300"
+# learn - Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+# bgscan="learn:<short bgscan interval in seconds>:<signal strength threshold>:
+# <long interval>[:<database file name>]"
+# bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
+#
+# This option can also be set outside of all network blocks for the bgscan
+# parameter to apply for all the networks that have no specific bgscan
+# parameter.
+#
# proto: list of accepted protocols
# WPA = WPA/IEEE 802.11i/D3.0
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
@@ -341,6 +572,16 @@ fast_reauth=1
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
# If not set, this defaults to: WPA-PSK WPA-EAP
#
+# ieee80211w: whether management frame protection is enabled
+# 0 = disabled (default unless changed with the global pmf parameter)
+# 1 = optional
+# 2 = required
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
# OPEN = Open System authentication (required for WPA/WPA2)
# SHARED = Shared Key authentication (requires static WEP keys)
@@ -366,7 +607,8 @@ fast_reauth=1
# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
# generated using the passphrase and SSID). ASCII passphrase must be between
-# 8 and 63 characters (inclusive).
+# 8 and 63 characters (inclusive). ext:<name of external PSK field> format can
+# be used to indicate that the PSK/passphrase is stored in external storage.
# This field is not needed, if WPA-EAP is used.
# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
@@ -389,7 +631,7 @@ fast_reauth=1
#
# proactive_key_caching:
# Enable/disable opportunistic PMKSA caching for WPA2.
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global okc parameter)
# 1 = enabled
#
# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
@@ -427,7 +669,8 @@ fast_reauth=1
# EAP-PSK/PAX/SAKE/GPSK.
# anonymous_identity: Anonymous identity string for EAP (to be used as the
# unencrypted identity with EAP types that support different tunnelled
-# identity, e.g., EAP-TTLS)
+# identity, e.g., EAP-TTLS). This field can also be used with
+# EAP-SIM/AKA/AKA' to store the pseudonym identity.
# password: Password string for EAP. This field can include either the
# plaintext password (using ASCII or hex string) or a NtPasswordHash
# (16-byte MD4 hash of password) in hash:<32 hex digits> format.
@@ -435,7 +678,8 @@ fast_reauth=1
# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
# EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
# PSK) is also configured using this field. For EAP-GPSK, this is a
-# variable length PSK.
+# variable length PSK. ext:<name of external password field> format can
+# be used to indicate that the password is stored in external storage.
# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
# or more trusted CA certificates. If ca_cert and ca_path are not
# included, server certificate will not be verified. This is insecure and
@@ -538,6 +782,25 @@ fast_reauth=1
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+#
+# TLS-based methods can use the following parameters to control TLS behavior
+# (these are normally in the phase1 parameter, but can be used also in the
+# phase2 parameter when EAP-TLS is used within the inner tunnel):
+# tls_allow_md5=1 - allow MD5-based certificate signatures (depending on the
+# TLS library, these may be disabled by default to enforce stronger
+# security)
+# tls_disable_time_checks=1 - ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# tls_disable_session_ticket=1 - disable TLS Session Ticket extension
+# tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used
+# Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS
+# as a workaround for broken authentication server implementations unless
+# EAP workarounds are disabled with eap_workarounds=0.
+# For EAP-FAST, this must be set to 0 (or left unconfigured for the
+# default value to be used automatically).
+#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
# ca_cert2: File path to CA certificate file. This file can have one or more
@@ -561,6 +824,11 @@ fast_reauth=1
# interface used for EAPOL. The default value is suitable for most
# cases.
#
+# ocsp: Whether to use/require OCSP to check server certificate
+# 0 = do not use OCSP stapling (TLS certificate status extension)
+# 1 = try to use OCSP stapling, but not require response
+# 2 = require valid OCSP stapling response
+#
# EAP-FAST variables:
# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
# to create this file and write updates to it when PAC is being
@@ -587,6 +855,71 @@ fast_reauth=1
# number of authentication servers. Strict EAP conformance mode can be
# configured by disabling workarounds with eap_workaround=0.
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+
+# DTIM period in Beacon intervals for AP mode (default: 2)
+#dtim_period=2
+
+# Beacon interval (default: 100 TU)
+#beacon_int=100
+
+# disable_ht: Whether HT (802.11n) should be disabled.
+# 0 = HT enabled (if AP supports it)
+# 1 = HT disabled
+#
+# disable_ht40: Whether HT-40 (802.11n) should be disabled.
+# 0 = HT-40 enabled (if AP supports it)
+# 1 = HT-40 disabled
+#
+# disable_sgi: Whether SGI (short guard interval) should be disabled.
+# 0 = SGI enabled (if AP supports it)
+# 1 = SGI disabled
+#
+# ht_mcs: Configure allowed MCS rates.
+# Parsed as an array of bytes, in base-16 (ascii-hex)
+# ht_mcs="" // Use all available (default)
+# ht_mcs="0xff 00 00 00 00 00 00 00 00 00 " // Use MCS 0-7 only
+# ht_mcs="0xff ff 00 00 00 00 00 00 00 00 " // Use MCS 0-15 only
+#
+# disable_max_amsdu: Whether MAX_AMSDU should be disabled.
+# -1 = Do not make any changes.
+# 0 = Enable MAX-AMSDU if hardware supports it.
+# 1 = Disable AMSDU
+#
+# ampdu_density: Allow overriding AMPDU density configuration.
+# Treated as hint by the kernel.
+# -1 = Do not make any changes.
+# 0-3 = Set AMPDU density (aka factor) to specified value.
+
+# disable_vht: Whether VHT should be disabled.
+# 0 = VHT enabled (if AP supports it)
+# 1 = VHT disabled
+#
+# vht_capa: VHT capabilities to set in the override
+# vht_capa_mask: mask of VHT capabilities
+#
+# vht_rx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for RX NSS 1-8
+# vht_tx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for TX NSS 1-8
+# 0: MCS 0-7
+# 1: MCS 0-8
+# 2: MCS 0-9
+# 3: not supported
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
@@ -833,7 +1166,19 @@ network={
}
-# IBSS/ad-hoc network with WPA-None/TKIP.
+# IBSS/ad-hoc network with RSN
+network={
+ ssid="ibss-rsn"
+ key_mgmt=WPA-PSK
+ proto=RSN
+ psk="12345678"
+ mode=1
+ frequency=2412
+ pairwise=CCMP
+ group=CCMP
+}
+
+# IBSS/ad-hoc network with WPA-None/TKIP (deprecated)
network={
ssid="test adhoc"
mode=1
@@ -919,3 +1264,10 @@ SGVsbG8gV29ybGQhCg==
network={
key_mgmt=NONE
}
+
+
+# Example config file that will only scan on channel 36.
+freq_list=5180
+network={
+ key_mgmt=NONE
+}
diff --git a/wpa_supplicant/wpa_supplicant.nsi b/wpa_supplicant/wpa_supplicant.nsi
deleted file mode 100644
index b9f0162..0000000
--- a/wpa_supplicant/wpa_supplicant.nsi
+++ /dev/null
@@ -1,112 +0,0 @@
-!define PRODUCT_NAME "wpa_supplicant"
-!define PRODUCT_VERSION "@WPAVER@"
-!define PRODUCT_PUBLISHER "Jouni Malinen"
-
-Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
-outfile "../wpa_supplicant-@WPAVER@.exe"
-
-installDir "$PROGRAMFILES\wpa_supplicant"
-
-Page Directory
-Page InstFiles
-
-section -Prerequisites
- SetOutPath $INSTDIR\Prerequisites
- MessageBox MB_YESNO "Install WinPcap?" /SD IDYES IDNO endWinPcap
- File "/opt/Qt-Win/files/WinPcap_4_1_2.exe"
- ExecWait "$INSTDIR\Prerequisites\WinPcap_4_1_2.exe"
- Goto endWinPcap
- endWinPcap:
-sectionEnd
-
-
-section
- setOutPath $INSTDIR
-
- File wpa_gui.exe
- File wpa_gui_de.qm
- File wpa_cli.exe
- File COPYING
- File README
- File README-Windows.txt
- File win_example.reg
- File win_if_list.exe
- File wpa_passphrase.exe
- File wpa_supplicant.conf
- File wpa_supplicant.exe
- File wpasvc.exe
-
- File /opt/Qt-Win/files/mingwm10.dll
- File /opt/Qt-Win/files/libgcc_s_dw2-1.dll
- File /opt/Qt-Win/files/QtCore4.dll
- File /opt/Qt-Win/files/QtGui4.dll
-
- WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_level" 0
- WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_show_keys" 0
- WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_timestamp" 0
- WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_use_file" 0
-
- WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "ap_scan" 2
- WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "update_config" 1
- WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default\networks" "dummy" 1
- DeleteRegValue HKLM "Software\wpa_supplicant\configs\default\networks" "dummy"
-
- WriteRegDWORD HKLM "Software\wpa_supplicant\interfaces" "dummy" 1
- DeleteRegValue HKLM "Software\wpa_supplicant\interfaces" "dummy"
-
- writeUninstaller "$INSTDIR\uninstall.exe"
-
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \
- "DisplayName" "wpa_supplicant"
-WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \
- "UninstallString" "$INSTDIR\uninstall.exe"
-
- CreateDirectory "$SMPROGRAMS\wpa_supplicant"
- CreateShortCut "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk" "$INSTDIR\wpa_gui.exe"
- CreateShortCut "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk" "$INSTDIR\uninstall.exe"
-
- ExecWait "$INSTDIR\wpasvc.exe reg"
-sectionEnd
-
-
-Function un.onInit
- MessageBox MB_YESNO "This will uninstall wpa_supplicant. Continue?" IDYES NoAbort
- Abort
- NoAbort:
-FunctionEnd
-
-section "uninstall"
- DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant"
- delete "$INSTDIR\uninstall.exe"
-
- ExecWait "$INSTDIR\wpasvc.exe unreg"
-
- DeleteRegKey HKLM "Software\wpa_supplicant"
-
- delete "$INSTDIR\wpa_gui.exe"
- delete "$INSTDIR\wpa_gui_de.qm"
- delete "$INSTDIR\wpa_cli.exe"
- delete "$INSTDIR\COPYING"
- delete "$INSTDIR\README"
- delete "$INSTDIR\README-Windows.txt"
- delete "$INSTDIR\win_example.reg"
- delete "$INSTDIR\win_if_list.exe"
- delete "$INSTDIR\wpa_passphrase.exe"
- delete "$INSTDIR\wpa_supplicant.conf"
- delete "$INSTDIR\wpa_supplicant.exe"
- delete "$INSTDIR\wpasvc.exe"
-
- delete "$INSTDIR\mingwm10.dll"
- delete "$INSTDIR\libgcc_s_dw2-1.dll"
- delete "$INSTDIR\QtCore4.dll"
- delete "$INSTDIR\QtGui4.dll"
-
- delete "$INSTDIR\Prerequisites\WinPcap_4_1_2.exe"
- rmdir "$INSTDIR\Prerequisites"
-
- rmdir "$INSTDIR"
-
- delete "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk"
- delete "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk"
- rmdir "$SMPROGRAMS\wpa_supplicant"
-sectionEnd
diff --git a/wpa_supplicant/wpa_supplicant_conf.mk b/wpa_supplicant/wpa_supplicant_conf.mk
new file mode 100644
index 0000000..74986ea
--- /dev/null
+++ b/wpa_supplicant/wpa_supplicant_conf.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+# Include this makefile to generate your hardware specific wpa_supplicant.conf
+# Requires: WIFI_DRIVER_SOCKET_IFACE
+
+LOCAL_PATH := $(call my-dir)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := wpa_supplicant.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/wifi
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+WPA_SUPPLICANT_CONF_TEMPLATE := $(LOCAL_PATH)/wpa_supplicant_template.conf
+WPA_SUPPLICANT_CONF_SCRIPT := $(LOCAL_PATH)/wpa_supplicant_conf.sh
+$(LOCAL_BUILT_MODULE): PRIVATE_WIFI_DRIVER_SOCKET_IFACE := $(WIFI_DRIVER_SOCKET_IFACE)
+$(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE := $(WPA_SUPPLICANT_CONF_TEMPLATE)
+$(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT := $(WPA_SUPPLICANT_CONF_SCRIPT)
+$(LOCAL_BUILT_MODULE) : $(WPA_SUPPLICANT_CONF_TEMPLATE) $(WPA_SUPPLICANT_CONF_SCRIPT)
+ @echo Target wpa_supplicant.conf: $@
+ @mkdir -p $(dir $@)
+ $(hide) WIFI_DRIVER_SOCKET_IFACE="$(PRIVATE_WIFI_DRIVER_SOCKET_IFACE)" \
+ bash $(PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT) $(PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE) > $@
+
+########################
diff --git a/wpa_supplicant/wpa_supplicant_conf.sh b/wpa_supplicant/wpa_supplicant_conf.sh
new file mode 100644
index 0000000..f36eef1
--- /dev/null
+++ b/wpa_supplicant/wpa_supplicant_conf.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+# Generate a wpa_supplicant.conf from the template.
+# $1: the template file name
+if [ -n "$WIFI_DRIVER_SOCKET_IFACE" ]
+then
+ sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1 | sed -e "s/wlan0/$WIFI_DRIVER_SOCKET_IFACE/"
+else
+ sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1
+fi
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 510f4ea..267c226 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1,15 +1,9 @@
/*
* wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WPA_SUPPLICANT_I_H
@@ -17,6 +11,8 @@
#include "utils/list.h"
#include "common/defs.h"
+#include "common/sae.h"
+#include "wps/wps_defs.h"
#include "config_ssid.h"
extern const char *wpa_supplicant_version;
@@ -36,6 +32,7 @@ struct scan_info;
struct wpa_bss;
struct wpa_scan_results;
struct hostapd_hw_modes;
+struct wpa_driver_associate_params;
/*
* Forward declarations of private structures used within the ctrl_iface
@@ -60,6 +57,14 @@ struct wpa_interface {
const char *confname;
/**
+ * confanother - Additional configuration name (file or profile) name
+ *
+ * This can also be %NULL when the additional configuration file is not
+ * used.
+ */
+ const char *confanother;
+
+ /**
* ctrl_interface - Control interface parameter
*
* If a configuration file is not used, this variable can be used to
@@ -100,6 +105,15 @@ struct wpa_interface {
* receiving of EAPOL frames from an additional interface.
*/
const char *bridge_ifname;
+
+ /**
+ * p2p_mgmt - Interface used for P2P management (P2P Device operations)
+ *
+ * Indicates whether wpas_p2p_init() must be called for this interface.
+ * This is used only when the driver supports a dedicated P2P Device
+ * interface that is not a network interface.
+ */
+ int p2p_mgmt;
};
/**
@@ -151,6 +165,11 @@ struct wpa_params {
char *ctrl_interface;
/**
+ * ctrl_interface_group - Global ctrl_iface group
+ */
+ char *ctrl_interface_group;
+
+ /**
* dbus_ctrl_interface - Enable the DBus control interface
*/
int dbus_ctrl_interface;
@@ -166,6 +185,11 @@ struct wpa_params {
int wpa_debug_syslog;
/**
+ * wpa_debug_tracing - Enable log output through Linux tracing
+ */
+ int wpa_debug_tracing;
+
+ /**
* override_driver - Optional driver parameter override
*
* This parameter can be used to override the driver parameter in
@@ -221,19 +245,112 @@ struct wpa_global {
struct p2p_data *p2p;
struct wpa_supplicant *p2p_init_wpa_s;
struct wpa_supplicant *p2p_group_formation;
+ struct wpa_supplicant *p2p_invite_group;
u8 p2p_dev_addr[ETH_ALEN];
+ struct os_reltime p2p_go_wait_client;
struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
int cross_connection;
+ struct wpa_freq_range_list p2p_disallow_freq;
+ struct wpa_freq_range_list p2p_go_avoid_freq;
+ enum wpa_conc_pref {
+ WPA_CONC_PREF_NOT_SET,
+ WPA_CONC_PREF_STA,
+ WPA_CONC_PREF_P2P
+ } conc_pref;
+ unsigned int p2p_per_sta_psk:1;
+ unsigned int p2p_fail_on_wps_complete:1;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ int wifi_display;
+#define MAX_WFD_SUBELEMS 10
+ struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ struct psk_list_entry *add_psk; /* From group formation */
+};
+
+
+/**
+ * struct wpa_radio - Internal data for per-radio information
+ *
+ * This structure is used to share data about configured interfaces
+ * (struct wpa_supplicant) that share the same physical radio, e.g., to allow
+ * better coordination of offchannel operations.
+ */
+struct wpa_radio {
+ char name[16]; /* from driver_ops get_radio_name() or empty if not
+ * available */
+ struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
+ struct dl_list work; /* struct wpa_radio_work::list entries */
+};
+
+/**
+ * struct wpa_radio_work - Radio work item
+ */
+struct wpa_radio_work {
+ struct dl_list list;
+ unsigned int freq; /* known frequency (MHz) or 0 for multiple/unknown */
+ const char *type;
+ struct wpa_supplicant *wpa_s;
+ void (*cb)(struct wpa_radio_work *work, int deinit);
+ void *ctx;
+ unsigned int started:1;
+ struct os_reltime time;
+};
+
+int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
+ const char *type, int next,
+ void (*cb)(struct wpa_radio_work *work, int deinit),
+ void *ctx);
+void radio_work_done(struct wpa_radio_work *work);
+void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s,
+ const char *type);
+void radio_work_check_next(struct wpa_supplicant *wpa_s);
+
+struct wpa_connect_work {
+ unsigned int sme:1;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid;
};
+int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
+ struct wpa_ssid *test_ssid);
+void wpas_connect_work_free(struct wpa_connect_work *cwork);
+void wpas_connect_work_done(struct wpa_supplicant *wpa_s);
+struct wpa_external_work {
+ unsigned int id;
+ char type[100];
+ unsigned int timeout;
+};
+
+/**
+ * offchannel_send_action_result - Result of offchannel send Action frame
+ */
enum offchannel_send_action_result {
- OFFCHANNEL_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
- OFFCHANNEL_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged
+ OFFCHANNEL_SEND_ACTION_SUCCESS /**< Frame was send and acknowledged */,
+ OFFCHANNEL_SEND_ACTION_NO_ACK /**< Frame was sent, but not acknowledged
*/,
- OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
+ OFFCHANNEL_SEND_ACTION_FAILED /**< Frame was not sent due to a failure
+ */
+};
+
+struct wps_ap_info {
+ u8 bssid[ETH_ALEN];
+ enum wps_ap_info_type {
+ WPS_AP_NOT_SEL_REG,
+ WPS_AP_SEL_REG,
+ WPS_AP_SEL_REG_OUR
+ } type;
+ unsigned int tries;
+ struct os_reltime last_attempt;
+};
+
+struct wpa_ssid_value {
+ u8 ssid[32];
+ size_t ssid_len;
};
/**
@@ -246,6 +363,8 @@ enum offchannel_send_action_result {
*/
struct wpa_supplicant {
struct wpa_global *global;
+ 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 *next;
struct l2_packet_data *l2;
@@ -258,13 +377,17 @@ struct wpa_supplicant {
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
char *dbus_new_path;
char *dbus_groupobj_path;
+#ifdef CONFIG_AP
+ char *preq_notify_peer;
+#endif /* CONFIG_AP */
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
char bridge_ifname[16];
char *confname;
+ char *confanother;
struct wpa_config *conf;
int countermeasures;
- os_time_t last_michael_mic_error;
+ struct os_reltime last_michael_mic_error;
u8 bssid[ETH_ALEN];
u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
* field contains the target BSSID. */
@@ -286,6 +409,19 @@ struct wpa_supplicant {
void *drv_priv; /* private data used by driver_ops */
void *global_drv_priv;
+ u8 *bssid_filter;
+ size_t bssid_filter_count;
+
+ u8 *disallow_aps_bssid;
+ size_t disallow_aps_bssid_count;
+ struct wpa_ssid_value *disallow_aps_ssid;
+ size_t disallow_aps_ssid_count;
+
+ enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;
+
+ /* previous scan was wildcard when interleaving between
+ * wildcard scans and specific SSID scan when max_ssids=1 */
+ int prev_scan_wildcard;
struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID;
* NULL = not yet initialized (start
* with wildcard SSID)
@@ -308,6 +444,15 @@ struct wpa_supplicant {
unsigned int bss_update_idx;
unsigned int bss_next_id;
+ /*
+ * Pointers to BSS entries in the order they were in the last scan
+ * results.
+ */
+ struct wpa_bss **last_scan_res;
+ unsigned int last_scan_res_used;
+ unsigned int last_scan_res_size;
+ struct os_reltime last_scan;
+
struct wpa_driver_ops *driver;
int interface_removed; /* whether the network interface has been
* removed */
@@ -317,29 +462,97 @@ struct wpa_supplicant {
struct ctrl_iface_priv *ctrl_iface;
enum wpa_states wpa_state;
+ struct wpa_radio_work *scan_work;
int scanning;
int sched_scanning;
int new_connection;
- int reassociated_connection;
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
struct scard_data *scard;
+ char imsi[20];
+ int mnc_len;
unsigned char last_eapol_src[ETH_ALEN];
- int keys_cleared;
+ unsigned int keys_cleared; /* bitfield of key indexes that the driver is
+ * known not to be configured with a key */
struct wpa_blacklist *blacklist;
- int scan_req; /* manual scan request; this forces a scan even if there
- * are no enabled networks in the configuration */
+ /**
+ * extra_blacklist_count - Sum of blacklist counts after last connection
+ *
+ * This variable is used to maintain a count of temporary blacklisting
+ * failures (maximum number for any BSS) over blacklist clear
+ * operations. This is needed for figuring out whether there has been
+ * failures prior to the last blacklist clear operation which happens
+ * whenever no other not-blacklisted BSS candidates are available. This
+ * gets cleared whenever a connection has been established successfully.
+ */
+ int extra_blacklist_count;
+
+ /**
+ * scan_req - Type of the scan request
+ */
+ enum scan_req_type {
+ /**
+ * NORMAL_SCAN_REQ - Normal scan request
+ *
+ * This is used for scans initiated by wpa_supplicant to find an
+ * AP for a connection.
+ */
+ NORMAL_SCAN_REQ,
+
+ /**
+ * INITIAL_SCAN_REQ - Initial scan request
+ *
+ * This is used for the first scan on an interface to force at
+ * least one scan to be run even if the configuration does not
+ * include any enabled networks.
+ */
+ INITIAL_SCAN_REQ,
+
+ /**
+ * MANUAL_SCAN_REQ - Manual scan request
+ *
+ * This is used for scans where the user request a scan or
+ * a specific wpa_supplicant operation (e.g., WPS) requires scan
+ * to be run.
+ */
+ MANUAL_SCAN_REQ
+ } scan_req, last_scan_req;
+ struct os_reltime scan_trigger_time, scan_start_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
+ int *manual_scan_freqs;
+ unsigned int manual_scan_passive:1;
+ unsigned int manual_scan_use_id:1;
+ unsigned int manual_scan_only_new:1;
+ unsigned int own_scan_requested:1;
+ unsigned int own_scan_running:1;
+ unsigned int external_scan_running:1;
+ unsigned int clear_driver_scan_cache:1;
+ unsigned int manual_scan_id;
int scan_interval; /* time in sec between scans to find suitable AP */
+ int normal_scans; /* normal scans run before sched_scan */
+ int scan_for_connection; /* whether the scan request was triggered for
+ * finding a connection */
unsigned int drv_flags;
+ unsigned int drv_enc;
+
+ /*
+ * A bitmap of supported protocols for probe response offload. See
+ * struct wpa_driver_capa in driver.h
+ */
+ unsigned int probe_resp_offloads;
+
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
int max_scan_ssids;
int max_sched_scan_ssids;
int sched_scan_supported;
@@ -357,8 +570,10 @@ struct wpa_supplicant {
int blacklist_cleared;
struct wpabuf *pending_eapol_rx;
- struct os_time pending_eapol_rx_time;
+ struct os_reltime pending_eapol_rx_time;
u8 pending_eapol_rx_src[ETH_ALEN];
+ unsigned int last_eapol_matches_bssid:1;
+ unsigned int eap_expected_failure:1;
struct ibss_rsn *ibss_rsn;
@@ -390,7 +605,15 @@ struct wpa_supplicant {
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending
* SA Query transaction identifiers */
- struct os_time sa_query_start;
+ struct os_reltime sa_query_start;
+ u8 sched_obss_scan;
+ u16 obss_scan_int;
+ u16 bss_max_idle_period;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+ struct wpabuf *sae_token;
+ int sae_group_index;
+#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -418,6 +641,8 @@ struct wpa_supplicant {
unsigned int roc_waiting_drv_freq;
int action_tx_wait_time;
+ int p2p_mgmt;
+
#ifdef CONFIG_P2P
struct p2p_go_neg_results *go_params;
int create_p2p_iface;
@@ -447,8 +672,15 @@ struct wpa_supplicant {
u8 pending_join_iface_addr[ETH_ALEN];
u8 pending_join_dev_addr[ETH_ALEN];
int pending_join_wps_method;
+ u8 p2p_join_ssid[32];
+ size_t p2p_join_ssid_len;
int p2p_join_scan_count;
+ int auto_pd_scan_retry;
int force_long_sd;
+ u16 pending_pd_config_methods;
+ enum {
+ NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+ } pending_pd_use;
/*
* Whether cross connection is disallowed by the AP to which this
@@ -471,24 +703,55 @@ struct wpa_supplicant {
*/
char cross_connect_uplink[100];
- enum {
- P2P_GROUP_REMOVAL_UNKNOWN,
- P2P_GROUP_REMOVAL_REQUESTED,
- P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
- P2P_GROUP_REMOVAL_UNAVAILABLE
- } removal_reason;
-
- unsigned int p2p_cb_on_scan_complete:1;
+ unsigned int p2p_auto_join:1;
+ unsigned int p2p_auto_pd:1;
+ unsigned int p2p_persistent_group:1;
+ unsigned int p2p_fallback_to_go_neg:1;
+ unsigned int p2p_pd_before_go_neg:1;
+ unsigned int p2p_go_ht40:1;
+ unsigned int p2p_go_vht:1;
+ unsigned int user_initiated_pd:1;
+ unsigned int p2p_go_group_formation_completed:1;
+ unsigned int waiting_presence_resp;
+ int p2p_first_connection_timeout;
+ unsigned int p2p_nfc_tag_enabled:1;
+ unsigned int p2p_peer_oob_pk_hash_known:1;
+ unsigned int p2p_disable_ip_addr_req:1;
+ int p2p_persistent_go_freq;
+ int p2p_persistent_id;
+ int p2p_go_intent;
+ int p2p_connect_freq;
+ struct os_reltime p2p_auto_started;
+ struct wpa_ssid *p2p_last_4way_hs_fail;
+ struct wpa_radio_work *p2p_scan_work;
+ struct wpa_radio_work *p2p_listen_work;
+ struct wpa_radio_work *p2p_send_action_work;
+
+ u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */
+ struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group
+ * formation */
+ u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+ u8 p2p_ip_addr_info[3 * 4];
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
const struct bgscan_ops *bgscan;
void *bgscan_priv;
+ const struct autoscan_ops *autoscan;
+ struct wpa_driver_scan_params *autoscan_params;
+ void *autoscan_priv;
+
struct wpa_ssid *connect_without_scan;
+ struct wps_ap_info *wps_ap;
+ size_t num_wps_ap;
+ int wps_ap_iter;
+
int after_wps;
+ int known_wps_freq;
unsigned int wps_freq;
+ u16 wps_ap_channel;
int wps_fragment_size;
int auto_reconnect_disabled;
@@ -503,6 +766,9 @@ struct wpa_supplicant {
unsigned int fetch_anqp_in_progress:1;
unsigned int network_select:1;
unsigned int auto_select:1;
+ unsigned int auto_network_select:1;
+ unsigned int fetch_all_anqp:1;
+ struct wpa_bss *interworking_gas_bss;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -511,11 +777,55 @@ struct wpa_supplicant {
u16 num_modes;
u16 flags;
} hw;
+
+ int pno;
+ int pno_sched_pending;
+
+ /* WLAN_REASON_* reason codes. Negative if locally generated. */
+ int disconnect_reason;
+
+ struct ext_password_data *ext_pw;
+
+ struct wpabuf *last_gas_resp, *prev_gas_resp;
+ u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN];
+ u8 last_gas_dialog_token, prev_gas_dialog_token;
+
+ unsigned int no_keep_alive:1;
+
+#ifdef CONFIG_WNM
+ u8 wnm_dialog_token;
+ u8 wnm_reply;
+ u8 wnm_num_neighbor_report;
+ u8 wnm_mode;
+ u16 wnm_dissoc_timer;
+ u8 wnm_validity_interval;
+ u8 wnm_bss_termination_duration[12];
+ struct neighbor_report *wnm_neighbor_report_elements;
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_TESTING_GET_GTK
+ u8 last_gtk[32];
+ size_t last_gtk_len;
+#endif /* CONFIG_TESTING_GET_GTK */
+
+ unsigned int num_multichan_concurrent;
+ struct wpa_radio_work *connect_work;
+
+ unsigned int ext_work_id;
};
/* wpa_supplicant.c */
+void wpa_supplicant_apply_ht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_vht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
+
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
@@ -534,6 +844,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec);
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state);
struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
@@ -541,8 +852,6 @@ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code);
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
- int reason_code);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
@@ -550,12 +859,17 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
+int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
+ const char *pkcs11_engine_path,
+ const char *pkcs11_module_path);
int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
int ap_scan);
int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
unsigned int expire_age);
int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
unsigned int expire_count);
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+ int scan_interval);
int wpa_supplicant_set_debug_params(struct wpa_global *global,
int debug_level, int debug_timestamp,
int debug_show_keys);
@@ -566,7 +880,8 @@ void wpa_show_license(void);
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
struct wpa_interface *iface);
int wpa_supplicant_remove_iface(struct wpa_global *global,
- struct wpa_supplicant *wpa_s);
+ struct wpa_supplicant *wpa_s,
+ int terminate);
struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
const char *ifname);
struct wpa_global * wpa_supplicant_init(struct wpa_params *params);
@@ -578,12 +893,19 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
void wpa_supplicant_terminate_proc(struct wpa_global *global);
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len);
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
-enum wpa_cipher cipher_suite2driver(int cipher);
void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s);
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int clear_failures);
+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);
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -607,6 +929,10 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **selected_ssid);
/* eap_register.c */
int eap_register_methods(void);
@@ -621,4 +947,13 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid)
return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
}
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+ int *freq_array, unsigned int len);
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+ int *freq_array, unsigned int len);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
new file mode 100644
index 0000000..a08eb33
--- /dev/null
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -0,0 +1,6 @@
+##### wpa_supplicant configuration file template #####
+update_config=1
+ctrl_interface=wlan0
+eapol_version=1
+ap_scan=1
+fast_reauth=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 69b0cf8..e8a4b35 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -222,20 +216,38 @@ static void wpa_supplicant_aborted_cached(void *ctx)
}
-static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+static const char * result_str(enum eapol_supp_result result)
+{
+ switch (result) {
+ case EAPOL_SUPP_RESULT_FAILURE:
+ return "FAILURE";
+ case EAPOL_SUPP_RESULT_SUCCESS:
+ return "SUCCESS";
+ case EAPOL_SUPP_RESULT_EXPECTED_FAILURE:
+ return "EXPECTED_FAILURE";
+ }
+ return "?";
+}
+
+
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
+ enum eapol_supp_result result,
void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
int res, pmk_len;
u8 pmk[PMK_LEN];
- wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
- success ? "" : "un");
+ wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s",
+ result_str(result));
if (wpas_wps_eapol_cb(wpa_s) > 0)
return;
- if (!success) {
+ wpa_s->eap_expected_failure = result ==
+ EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+
+ if (result != EAPOL_SUPP_RESULT_SUCCESS) {
/*
* Make sure we do not get stuck here waiting for long EAPOL
* timeout if the AP does not disconnect in case of
@@ -244,7 +256,8 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
}
- if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (result != EAPOL_SUPP_RESULT_SUCCESS ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
return;
if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -412,14 +425,6 @@ static enum wpa_states _wpa_supplicant_get_state(void *wpa_s)
}
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
- wpa_supplicant_disassociate(wpa_s, reason_code);
- /* Schedule a scan to make sure we continue looking for networks */
- wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -451,6 +456,13 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
/* Clear the MIC error counter when setting a new PTK. */
wpa_s->mic_errors_seen = 0;
}
+#ifdef CONFIG_TESTING_GET_GTK
+ if (key_idx > 0 && addr && is_broadcast_ether_addr(addr) &&
+ alg != WPA_ALG_NONE && key_len <= sizeof(wpa_s->last_gtk)) {
+ os_memcpy(wpa_s->last_gtk, key, key_len);
+ wpa_s->last_gtk_len = key_len;
+ }
+#endif /* CONFIG_TESTING_GET_GTK */
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
key, key_len);
}
@@ -520,8 +532,6 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
}
#endif /* CONFIG_IEEE80211R */
-#endif /* CONFIG_NO_WPA */
-
#ifdef CONFIG_TDLS
@@ -565,27 +575,52 @@ static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
static int wpa_supplicant_tdls_peer_addset(
- void *ctx, const u8 *peer, int add, u16 capability,
- const u8 *supp_rates, size_t supp_rates_len)
+ void *ctx, const u8 *peer, int add, u16 aid, u16 capability,
+ const u8 *supp_rates, size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
+ const u8 *supp_channels, size_t supp_channels_len,
+ const u8 *supp_oper_classes, size_t supp_oper_classes_len)
{
struct wpa_supplicant *wpa_s = ctx;
struct hostapd_sta_add_params params;
+ os_memset(&params, 0, sizeof(params));
+
params.addr = peer;
- params.aid = 1;
+ params.aid = aid;
params.capability = capability;
params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
- params.ht_capabilities = NULL;
+
+ /*
+ * TDLS Setup frames do not contain WMM IEs, hence need to depend on
+ * qosinfo to check if the peer is WMM capable.
+ */
+ if (qosinfo)
+ params.flags |= WPA_STA_WMM;
+
+ params.ht_capabilities = ht_capab;
+ params.vht_capabilities = vht_capab;
+ params.qosinfo = qosinfo;
params.listen_interval = 0;
params.supp_rates = supp_rates;
params.supp_rates_len = supp_rates_len;
params.set = !add;
+ params.ext_capab = ext_capab;
+ params.ext_capab_len = ext_capab_len;
+ params.supp_channels = supp_channels;
+ params.supp_channels_len = supp_channels_len;
+ params.supp_oper_classes = supp_oper_classes;
+ params.supp_oper_classes_len = supp_oper_classes_len;
return wpa_drv_sta_add(wpa_s, &params);
}
#endif /* CONFIG_TDLS */
+#endif /* CONFIG_NO_WPA */
+
enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
{
@@ -601,6 +636,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
return WPA_CTRL_REQ_EAP_OTP;
else if (os_strcmp(field, "PASSPHRASE") == 0)
return WPA_CTRL_REQ_EAP_PASSPHRASE;
+ else if (os_strcmp(field, "SIM") == 0)
+ return WPA_CTRL_REQ_SIM;
return WPA_CTRL_REQ_UNKNOWN;
}
@@ -637,6 +674,9 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
*txt = "Private key passphrase";
ret = "PASSPHRASE";
break;
+ case WPA_CTRL_REQ_SIM:
+ ret = "SIM";
+ break;
default:
break;
}
@@ -676,6 +716,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
return;
}
+ wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name);
+
buflen = 100 + os_strlen(txt) + ssid->ssid_len;
buf = os_malloc(buflen);
if (buf == NULL)
@@ -726,6 +768,53 @@ static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
}
+
+
+static void wpa_supplicant_status_cb(void *ctx, const char *status,
+ const char *parameter)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpas_notify_eap_status(wpa_s, status, parameter);
+}
+
+
+static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ char *str;
+ int res;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+ id, len);
+
+ if (wpa_s->current_ssid == NULL)
+ return;
+
+ if (id == NULL) {
+ if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ "NULL", 0) < 0)
+ return;
+ } else {
+ str = os_malloc(len * 2 + 1);
+ if (str == NULL)
+ return;
+ wpa_snprintf_hex(str, len * 2 + 1, id, len);
+ res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ str, 0);
+ os_free(str);
+ if (res < 0)
+ return;
+ }
+
+ if (wpa_s->conf->update_config) {
+ res = wpa_config_write(wpa_s->confname, wpa_s->conf);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to update config after "
+ "anonymous_id update");
+ }
+ }
+}
#endif /* IEEE8021X_EAPOL */
@@ -746,8 +835,10 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
ctx->set_wep_key = wpa_eapol_set_wep_key;
+#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
ctx->aborted_cached = wpa_supplicant_aborted_cached;
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
@@ -757,6 +848,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
+ ctx->status_cb = wpa_supplicant_status_cb;
+ ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
@@ -771,6 +864,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
}
+#ifndef CONFIG_NO_WPA
static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
const u8 *kck,
const u8 *replay_ctr)
@@ -779,6 +873,7 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
}
+#endif /* CONFIG_NO_WPA */
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
@@ -796,7 +891,6 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
- ctx->disassociate = _wpa_supplicant_disassociate;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -846,13 +940,30 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
conf.peerkey_enabled = ssid->peerkey;
conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
#ifdef IEEE8021X_EAPOL
- conf.proactive_key_caching = ssid->proactive_key_caching;
+ conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc : ssid->proactive_key_caching;
conf.eap_workaround = ssid->eap_workaround;
conf.eap_conf_ctx = &ssid->eap;
#endif /* IEEE8021X_EAPOL */
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group && wpa_s->current_bss &&
+ !wpa_s->p2p_disable_ip_addr_req) {
+ struct wpabuf *p2p;
+ p2p = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+ P2P_IE_VENDOR_TYPE);
+ if (p2p) {
+ u8 group_capab;
+ group_capab = p2p_get_group_capab(p2p);
+ if (group_capab &
+ P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION)
+ conf.p2p = 1;
+ wpabuf_free(p2p);
+ }
+ }
+#endif /* CONFIG_P2P */
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h
index 78c1b3d..9808c22 100644
--- a/wpa_supplicant/wpas_glue.h
+++ b/wpa_supplicant/wpas_glue.h
@@ -2,14 +2,8 @@
* WPA Supplicant - Glue code to setup EAPOL and RSN modules
* Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WPAS_GLUE_H
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 2b8b5ef..537aac3 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1,15 +1,9 @@
/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -17,6 +11,7 @@
#include "common.h"
#include "eloop.h"
#include "uuid.h"
+#include "crypto/random.h"
#include "crypto/dh_group5.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -26,6 +21,7 @@
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
+#include "wps/wps_attr_parse.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -47,8 +43,22 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
+static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
+{
+ os_free(wpa_s->wps_ap);
+ wpa_s->wps_ap = NULL;
+ wpa_s->num_wps_ap = 0;
+ wpa_s->wps_ap_iter = 0;
+}
+
+
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
+#ifdef CONFIG_P2P
+ if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
+ return 1;
+#endif /* CONFIG_P2P */
+
if (!wpa_s->wps_success &&
wpa_s->current_ssid &&
eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
@@ -70,6 +80,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
return 1;
}
+ wpas_wps_clear_ap_info(wpa_s);
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
@@ -78,6 +89,10 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
int disabled = wpa_s->current_ssid->disabled;
unsigned int freq = wpa_s->assoc_freq;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = NULL;
+ int use_fast_assoc = 0;
+
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential "
"(freq=%u)", freq);
@@ -90,8 +105,28 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
}
wpa_s->after_wps = 5;
wpa_s->wps_freq = freq;
+ wpa_s->normal_scans = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
+ "without a new scan can be used");
+ bss = wpa_supplicant_pick_network(wpa_s, &ssid);
+ if (bss) {
+ struct wpabuf *wps;
+ struct wps_parse_attr attr;
+
+ wps = wpa_bss_get_vendor_ie_multi(bss,
+ WPS_IE_VENDOR_TYPE);
+ if (wps && wps_parse_msg(wps, &attr) == 0 &&
+ attr.wps_state &&
+ *attr.wps_state == WPS_STATE_CONFIGURED)
+ use_fast_assoc = 1;
+ wpabuf_free(wps);
+ }
+
+ if (!use_fast_assoc ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
return 1;
}
@@ -189,6 +224,55 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
}
+static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *new_ssid)
+{
+ struct wpa_ssid *ssid, *next;
+
+ for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
+ ssid = next, next = ssid ? ssid->next : NULL) {
+ /*
+ * new_ssid has already been added to the list in
+ * wpas_wps_add_network(), so skip it.
+ */
+ if (ssid == new_ssid)
+ continue;
+
+ if (ssid->bssid_set || new_ssid->bssid_set) {
+ if (ssid->bssid_set != new_ssid->bssid_set)
+ continue;
+ if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) !=
+ 0)
+ continue;
+ }
+
+ /* compare SSID */
+ if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
+ continue;
+
+ if (ssid->ssid && new_ssid->ssid) {
+ if (os_memcmp(ssid->ssid, new_ssid->ssid,
+ ssid->ssid_len) != 0)
+ continue;
+ } else if (ssid->ssid || new_ssid->ssid)
+ continue;
+
+ /* compare security parameters */
+ if (ssid->auth_alg != new_ssid->auth_alg ||
+ ssid->key_mgmt != new_ssid->key_mgmt ||
+ ssid->proto != new_ssid->proto ||
+ ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
+ ssid->group_cipher != new_ssid->group_cipher)
+ continue;
+
+ /* Remove the duplicated older network entry. */
+ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ }
+}
+
+
static int wpa_supplicant_wps_cred(void *ctx,
const struct wps_credential *cred)
{
@@ -249,6 +333,15 @@ static int wpa_supplicant_wps_cred(void *ctx,
return 0;
}
+ if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+ if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+ wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+ "invalid Network Key length %lu",
+ (unsigned long) cred->key_len);
+ return -1;
+ }
+ }
+
if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
"on the received credential");
@@ -266,9 +359,13 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid->eap.phase1 = NULL;
os_free(ssid->eap.eap_methods);
ssid->eap.eap_methods = NULL;
- if (!ssid->p2p_group)
+ if (!ssid->p2p_group) {
ssid->temporary = 0;
- ssid->bssid_set = 0;
+ ssid->bssid_set = 0;
+ }
+ ssid->disabled_until.sec = 0;
+ ssid->disabled_until.usec = 0;
+ ssid->auth_failures = 0;
} else {
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
"received credential");
@@ -356,16 +453,6 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_WPA;
break;
- case WPS_AUTH_WPA:
- ssid->auth_alg = WPA_AUTH_ALG_OPEN;
- ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- ssid->proto = WPA_PROTO_WPA;
- break;
- case WPS_AUTH_WPA2:
- ssid->auth_alg = WPA_AUTH_ALG_OPEN;
- ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- ssid->proto = WPA_PROTO_RSN;
- break;
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -402,6 +489,11 @@ static int wpa_supplicant_wps_cred(void *ctx,
wpas_wps_security_workaround(wpa_s, ssid, cred);
+ if (cred->ap_channel)
+ wpa_s->wps_ap_channel = cred->ap_channel;
+
+ wpas_wps_remove_dup_network(wpa_s, ssid);
+
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -410,6 +502,13 @@ static int wpa_supplicant_wps_cred(void *ctx,
}
#endif /* CONFIG_NO_CONFIG_WRITE */
+ /*
+ * Optimize the post-WPS scan based on the channel used during
+ * the provisioning in case EAP-Failure is not received.
+ */
+ wpa_s->after_wps = 5;
+ wpa_s->wps_freq = wpa_s->assoc_freq;
+
return 0;
}
@@ -448,11 +547,13 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
}
-static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
- "No Error", /* WPS_EI_NO_ERROR */
- "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
- "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
-};
+static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
+ wpas_clear_wps(wpa_s);
+}
+
static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail)
@@ -462,13 +563,13 @@ 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 reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
- wps_event_fail_reason[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
"msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error,
fail->error_indication,
- wps_event_fail_reason[fail->error_indication]);
+ wps_ei_str(fail->error_indication));
} else {
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
@@ -478,7 +579,14 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
- wpas_clear_wps(wpa_s);
+
+ /*
+ * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
+ eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
+
wpas_notify_wps_event_fail(wpa_s, fail);
#ifdef CONFIG_P2P
wpas_p2p_wps_failed(wpa_s, fail);
@@ -486,11 +594,61 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
}
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+ int changed = 0;
+
+ eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid->disabled_for_connect && ssid->disabled) {
+ ssid->disabled_for_connect = 0;
+ ssid->disabled = 0;
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
+ changed++;
+ }
+ }
+
+ if (changed) {
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_printf(MSG_DEBUG, "WPS: Failed to update "
+ "configuration");
+ }
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ }
+}
+
+
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ /* Enable the networks disabled during wpas_wps_reassoc */
+ wpas_wps_reenable_networks(wpa_s);
+}
+
+
static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
wpa_s->wps_success = 1;
wpas_notify_wps_event_success(wpa_s);
+ if (wpa_s->current_ssid)
+ wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
+ wpa_s->extra_blacklist_count = 0;
+
+ /*
+ * Enable the networks disabled during wpas_wps_reassoc after 10
+ * seconds. The 10 seconds timer is to allow the data connection to be
+ * formed before allowing other networks to be selected.
+ */
+ eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+ NULL);
+
#ifdef CONFIG_P2P
wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
#endif /* CONFIG_P2P */
@@ -644,6 +802,12 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
break;
case WPS_EV_PBC_TIMEOUT:
break;
+ case WPS_EV_PBC_ACTIVE:
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
+ break;
+ case WPS_EV_PBC_DISABLE:
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
+ break;
case WPS_EV_ER_AP_ADD:
wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
break;
@@ -672,6 +836,17 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
}
+static int wpa_supplicant_wps_rf_band(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
+ return 0;
+
+ return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
+}
+
+
enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
{
if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
@@ -687,18 +862,24 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
int id;
struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+
prev_current = wpa_s->current_ssid;
+ /* Enable the networks disabled during wpas_wps_reassoc */
+ wpas_wps_reenable_networks(wpa_s);
+
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
/* Remove any existing WPS network from configuration */
ssid = wpa_s->conf->ssid;
while (ssid) {
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
if (ssid == wpa_s->current_ssid) {
- wpa_s->current_ssid = NULL;
- if (ssid != NULL)
- wpas_notify_network_changed(wpa_s);
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
id = ssid->id;
remove_ssid = ssid;
@@ -715,6 +896,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
wpa_config_remove_network(wpa_s->conf, id);
}
}
+
+ wpas_wps_clear_ap_info(wpa_s);
}
@@ -728,7 +911,8 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
- int registrar, const u8 *bssid)
+ int registrar, const u8 *dev_addr,
+ const u8 *bssid)
{
struct wpa_ssid *ssid;
@@ -748,6 +932,11 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
return NULL;
}
+#ifdef CONFIG_P2P
+ if (dev_addr)
+ os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
+#endif /* CONFIG_P2P */
+
if (bssid) {
#ifndef CONFIG_P2P
struct wpa_bss *bss;
@@ -793,8 +982,8 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
}
-static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *selected)
+static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *selected)
{
struct wpa_ssid *ssid;
@@ -806,6 +995,7 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
ssid = wpa_s->conf->ssid;
while (ssid) {
int was_disabled = ssid->disabled;
+ ssid->disabled_for_connect = 0;
/*
* In case the network object corresponds to a persistent group
* then do not send out network disabled signal. In addition,
@@ -814,17 +1004,47 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
*/
if (was_disabled != 2) {
ssid->disabled = ssid != selected;
- if (was_disabled != ssid->disabled)
+ if (was_disabled != ssid->disabled) {
+ if (ssid->disabled)
+ ssid->disabled_for_connect = 1;
wpas_notify_network_enabled_changed(wpa_s,
ssid);
+ }
}
ssid = ssid->next;
}
+}
+
+
+static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *selected, const u8 *bssid,
+ int freq)
+{
+ struct wpa_bss *bss;
+
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+ if (freq) {
+ wpa_s->after_wps = 5;
+ wpa_s->wps_freq = freq;
+ } else if (bssid) {
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss && bss->freq > 0) {
+ wpa_s->known_wps_freq = 1;
+ wpa_s->wps_freq = bss->freq;
+ }
+ }
+
+ wpas_wps_temp_disable(wpa_s, selected);
+
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
+ wpa_s->normal_scans = 0;
wpa_s->wps_success = 0;
wpa_s->blacklist_cleared = 0;
+
+ wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -834,7 +1054,7 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
{
struct wpa_ssid *ssid;
wpas_clear_wps(wpa_s);
- ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+ ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
if (ssid == NULL)
return -1;
ssid->temporary = 1;
@@ -851,29 +1071,53 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
}
#endif /* CONFIG_P2P */
- wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+ if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+ return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
- wpas_wps_reassoc(wpa_s, ssid);
+ wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
return 0;
}
-int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, int p2p_group, u16 dev_pw_id)
+static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, const u8 *bssid,
+ const char *pin, int p2p_group, u16 dev_pw_id,
+ const u8 *peer_pubkey_hash,
+ const u8 *ssid_val, size_t ssid_len, int freq)
{
struct wpa_ssid *ssid;
- char val[128];
+ char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN];
unsigned int rpin = 0;
+ char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
wpas_clear_wps(wpa_s);
- ssid = wpas_wps_add_network(wpa_s, 0, bssid);
- if (ssid == NULL)
+ if (bssid && is_zero_ether_addr(bssid))
+ bssid = NULL;
+ ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not add network");
return -1;
+ }
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ if (ssid_val) {
+ ssid->ssid = os_malloc(ssid_len);
+ if (ssid->ssid) {
+ os_memcpy(ssid->ssid, ssid_val, ssid_len);
+ ssid->ssid_len = ssid_len;
+ }
+ }
+ if (peer_pubkey_hash) {
+ os_memcpy(hash, " pkhash=", 8);
+ wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8,
+ peer_pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN);
+ } else {
+ hash[0] = '\0';
+ }
#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);
@@ -887,23 +1131,38 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
#endif /* CONFIG_P2P */
if (pin)
- os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",
- pin, dev_pw_id);
- else {
+ os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"",
+ pin, dev_pw_id, hash);
+ else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
+ os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
+ dev_pw_id, hash);
+ } else {
rpin = wps_generate_pin();
- os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
- rpin, dev_pw_id);
+ os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
+ rpin, dev_pw_id, hash);
+ }
+ if (wpa_config_set(ssid, "phase1", val, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
+ return -1;
}
- wpa_config_set(ssid, "phase1", val, 0);
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
- wpas_wps_reassoc(wpa_s, ssid);
+ wpa_s->wps_ap_iter = 1;
+ wpas_wps_reassoc(wpa_s, ssid, bssid, freq);
return rpin;
}
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *pin, int p2p_group, u16 dev_pw_id)
+{
+ return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
+ dev_pw_id, NULL, NULL, 0, 0);
+}
+
+
/* Cancel the wps pbc/pin requests */
int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
{
@@ -925,61 +1184,18 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpas_clear_wps(wpa_s);
+ } else {
+ wpas_wps_reenable_networks(wpa_s);
+ wpas_wps_clear_ap_info(wpa_s);
+ if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) >
+ 0)
+ wpas_clear_wps(wpa_s);
}
- return 0;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
- char *path, char *method, char *name)
-{
- struct wps_context *wps = wpa_s->wps;
- struct oob_device_data *oob_dev;
-
- oob_dev = wps_get_oob_device(device_type);
- if (oob_dev == NULL)
- return -1;
- oob_dev->device_path = path;
- oob_dev->device_name = name;
- wps->oob_conf.oob_method = wps_get_oob_method(method);
-
- if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E) {
- /*
- * Use pre-configured DH keys in order to be able to write the
- * key hash into the OOB file.
- */
- wpabuf_free(wps->dh_pubkey);
- wpabuf_free(wps->dh_privkey);
- wps->dh_privkey = NULL;
- wps->dh_pubkey = NULL;
- dh5_free(wps->dh_ctx);
- wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
- wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
- if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
- "Diffie-Hellman handshake");
- return -1;
- }
- }
-
- if (wps->oob_conf.oob_method == OOB_METHOD_CRED)
- wpas_clear_wps(wpa_s);
-
- if (wps_process_oob(wps, oob_dev, 0) < 0)
- return -1;
-
- if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
- wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
- wpas_wps_start_pin(wpa_s, NULL,
- wpabuf_head(wps->oob_conf.dev_password), 0,
- DEV_PW_DEFAULT) < 0)
- return -1;
+ wpa_s->after_wps = 0;
return 0;
}
-#endif /* CONFIG_WPS_OOB */
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
@@ -993,7 +1209,7 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
if (!pin)
return -1;
wpas_clear_wps(wpa_s);
- ssid = wpas_wps_add_network(wpa_s, 1, bssid);
+ ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
if (ssid == NULL)
return -1;
ssid->temporary = 1;
@@ -1015,21 +1231,31 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
res = os_snprintf(pos, end - pos, "\"");
if (res < 0 || res >= end - pos)
return -1;
- wpa_config_set(ssid, "phase1", val, 0);
+ if (wpa_config_set(ssid, "phase1", val, 0) < 0)
+ return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
- wpas_wps_reassoc(wpa_s, ssid);
+ wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
return 0;
}
-static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
+ const u8 *p2p_dev_addr, const u8 *psk,
size_t psk_len)
{
- wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
- "STA " MACSTR, MAC2STR(mac_addr));
+ if (is_zero_ether_addr(p2p_dev_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
+ MAC2STR(mac_addr));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
+ " P2P Device Addr " MACSTR,
+ MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
+ }
wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
/* TODO */
@@ -1102,7 +1328,9 @@ static u16 wps_fix_config_methods(u16 config_methods)
static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
struct wps_context *wps)
{
- wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname);
+ char buf[50];
+ const char *src;
+
if (is_nil_uuid(wpa_s->conf->uuid)) {
struct wpa_supplicant *first;
first = wpa_s->global->ifaces;
@@ -1113,17 +1341,34 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
os_memcpy(wps->uuid,
wpa_s->global->ifaces->wps->uuid,
WPS_UUID_LEN);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
- "interface", wps->uuid, WPS_UUID_LEN);
+ src = "from the first interface";
} else {
uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
- "address", wps->uuid, WPS_UUID_LEN);
+ src = "based on MAC address";
}
} else {
os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration",
- wps->uuid, WPS_UUID_LEN);
+ src = "based on configuration";
+ }
+
+ uuid_bin2str(wps->uuid, buf, sizeof(buf));
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf);
+}
+
+
+static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
+ struct wps_context *wps)
+{
+ wpabuf_free(wps->dev.vendor_ext_m1);
+ wps->dev.vendor_ext_m1 = NULL;
+
+ if (wpa_s->conf->wps_vendor_ext_m1) {
+ wps->dev.vendor_ext_m1 =
+ wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
+ if (!wps->dev.vendor_ext_m1) {
+ wpa_printf(MSG_ERROR, "WPS: Cannot "
+ "allocate memory for vendor_ext_m1");
+ }
}
}
@@ -1141,6 +1386,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
wps->cred_cb = wpa_supplicant_wps_cred;
wps->event_cb = wpa_supplicant_wps_event;
+ wps->rf_band_cb = wpa_supplicant_wps_rf_band;
wps->cb_ctx = wpa_s;
wps->dev.device_name = wpa_s->conf->device_name;
@@ -1166,6 +1412,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
+ wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
modes = wpa_s->hw.modes;
if (modes) {
@@ -1209,9 +1457,26 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_WPS_ER
+static void wpas_wps_nfc_clear(struct wps_context *wps)
+{
+ wps->ap_nfc_dev_pw_id = 0;
+ wpabuf_free(wps->ap_nfc_dh_pubkey);
+ wps->ap_nfc_dh_pubkey = NULL;
+ wpabuf_free(wps->ap_nfc_dh_privkey);
+ wps->ap_nfc_dh_privkey = NULL;
+ wpabuf_free(wps->ap_nfc_dev_pw);
+ wps->ap_nfc_dev_pw = NULL;
+}
+#endif /* CONFIG_WPS_ER */
+
+
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+ wpas_wps_clear_ap_info(wpa_s);
if (wpa_s->wps == NULL)
return;
@@ -1219,13 +1484,13 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_WPS_ER
wps_er_deinit(wpa_s->wps_er, NULL, NULL);
wpa_s->wps_er = NULL;
+ wpas_wps_nfc_clear(wpa_s->wps);
#endif /* CONFIG_WPS_ER */
wps_registrar_deinit(wpa_s->wps->registrar);
wpabuf_free(wpa_s->wps->dh_pubkey);
wpabuf_free(wpa_s->wps->dh_privkey);
- wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
- wpabuf_free(wpa_s->wps->oob_conf.dev_password);
+ wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
os_free(wpa_s->wps->network_key);
os_free(wpa_s->wps);
wpa_s->wps = NULL;
@@ -1233,14 +1498,14 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, struct wpa_scan_res *bss)
+ struct wpa_ssid *ssid, struct wpa_bss *bss)
{
struct wpabuf *wps_ie;
if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
return -1;
- wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
if (!wps_ie) {
wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
@@ -1302,19 +1567,19 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_scan_res *bss)
+ struct wpa_bss *bss)
{
struct wpabuf *wps_ie = NULL;
int ret = 0;
if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
- wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
/* allow wildcard SSID for WPS PBC */
ret = 1;
}
} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
- wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
if (wps_ie &&
(wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
@@ -1336,7 +1601,7 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
ret = 0;
if (bss->beacon_ie_len) {
struct wpabuf *bcn_wps;
- bcn_wps = wpa_scan_get_vendor_ie_multi_beacon(
+ bcn_wps = wpa_bss_get_vendor_ie_multi_beacon(
bss, WPS_IE_VENDOR_TYPE);
if (bcn_wps == NULL) {
wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
@@ -1518,91 +1783,128 @@ int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
const char *uuid, const char *pin)
{
u8 u[UUID_LEN];
- int any = 0;
-
- if (os_strcmp(uuid, "any") == 0)
- any = 1;
- else if (uuid_str2bin(uuid, u))
+ const u8 *use_uuid = NULL;
+ u8 addr_buf[ETH_ALEN];
+
+ if (os_strcmp(uuid, "any") == 0) {
+ } else if (uuid_str2bin(uuid, u) == 0) {
+ use_uuid = u;
+ } else if (hwaddr_aton(uuid, addr_buf) == 0) {
+ use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
+ if (use_uuid == NULL)
+ return -1;
+ } else
return -1;
return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
- any ? NULL : u,
+ use_uuid,
(const u8 *) pin, os_strlen(pin), 300);
}
int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_pbc(wpa_s->wps_er, u);
+ return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
}
int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+
+ return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
os_strlen(pin));
}
-int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
- int id)
+static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
+ struct wps_credential *cred)
{
- u8 u[UUID_LEN];
- struct wpa_ssid *ssid;
- struct wps_credential cred;
-
- if (uuid_str2bin(uuid, u))
- return -1;
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL || ssid->ssid == NULL)
- return -1;
-
- os_memset(&cred, 0, sizeof(cred));
+ os_memset(cred, 0, sizeof(*cred));
if (ssid->ssid_len > 32)
return -1;
- os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
- cred.ssid_len = ssid->ssid_len;
+ os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
+ cred->ssid_len = ssid->ssid_len;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+ cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- cred.encr_type = WPS_ENCR_AES;
+ cred->encr_type = WPS_ENCR_AES;
else
- cred.encr_type = WPS_ENCR_TKIP;
+ cred->encr_type = WPS_ENCR_TKIP;
if (ssid->passphrase) {
- cred.key_len = os_strlen(ssid->passphrase);
- if (cred.key_len >= 64)
+ cred->key_len = os_strlen(ssid->passphrase);
+ if (cred->key_len >= 64)
return -1;
- os_memcpy(cred.key, ssid->passphrase, cred.key_len);
+ os_memcpy(cred->key, ssid->passphrase, cred->key_len);
} else if (ssid->psk_set) {
- cred.key_len = 32;
- os_memcpy(cred.key, ssid->psk, 32);
+ cred->key_len = 32;
+ os_memcpy(cred->key, ssid->psk, 32);
} else
return -1;
} else {
- cred.auth_type = WPS_AUTH_OPEN;
- cred.encr_type = WPS_ENCR_NONE;
+ cred->auth_type = WPS_AUTH_OPEN;
+ cred->encr_type = WPS_ENCR_NONE;
}
- return wps_er_set_config(wpa_s->wps_er, u, &cred);
+
+ return 0;
+}
+
+
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+ int id)
+{
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+ struct wpa_ssid *ssid;
+ struct wps_credential cred;
+
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return -1;
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL || ssid->ssid == NULL)
+ return -1;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return -1;
+ return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
}
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
struct wps_credential cred;
size_t len;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
if (settings->ssid_hex == NULL || settings->auth == NULL ||
settings->encr == NULL || settings->key_hex == NULL)
@@ -1641,11 +1943,44 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
else
return -1;
- return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
- os_strlen(pin), &cred);
+ return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
+ (const u8 *) pin, os_strlen(pin), &cred);
}
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *uuid)
+{
+ struct wpabuf *ret;
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+
+ if (!wpa_s->wps_er)
+ return NULL;
+
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return NULL;
+
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
static int callbacks_pending = 0;
static void wpas_wps_terminate_cb(void *ctx)
@@ -1671,19 +2006,6 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
}
-int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ssid *ssid;
-
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
- if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS)
- return 1;
- }
-
- return 0;
-}
-
-
void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
{
struct wps_context *wps = wpa_s->wps;
@@ -1704,6 +2026,7 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
}
}
wps->config_methods = wps_fix_config_methods(wps->config_methods);
+ wps->dev.config_methods = wps->config_methods;
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
@@ -1715,6 +2038,9 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
}
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
+ wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
@@ -1731,3 +2057,730 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
wps->dev.serial_number = wpa_s->conf->serial_number;
}
}
+
+
+#ifdef CONFIG_WPS_NFC
+
+#ifdef CONFIG_WPS_ER
+static struct wpabuf *
+wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
+ struct wpa_ssid *ssid)
+{
+ struct wpabuf *ret;
+ struct wps_credential cred;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return NULL;
+
+ ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_ER */
+
+
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str)
+{
+#ifdef CONFIG_WPS_ER
+ if (id_str) {
+ int id;
+ char *end = NULL;
+ struct wpa_ssid *ssid;
+
+ id = strtol(id_str, &end, 10);
+ if (end && *end)
+ return NULL;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL)
+ return NULL;
+ return wpas_wps_network_config_token(wpa_s, ndef, ssid);
+ }
+#endif /* CONFIG_WPS_ER */
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface)
+ return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
+#endif /* CONFIG_AP */
+ return NULL;
+}
+
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
+{
+ if (wpa_s->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ wpa_s->conf->wps_nfc_dev_pw_id,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ wpa_s->conf->wps_nfc_dev_pw);
+ }
+
+ return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
+ &wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey,
+ &wpa_s->conf->wps_nfc_dev_pw);
+}
+
+
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
+ const u8 *bssid,
+ const struct wpabuf *dev_pw, u16 dev_pw_id,
+ int p2p_group, const u8 *peer_pubkey_hash,
+ const u8 *ssid, size_t ssid_len, int freq)
+{
+ struct wps_context *wps = wpa_s->wps;
+ char pw[32 * 2 + 1];
+
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
+ dev_pw = wpa_s->conf->wps_nfc_dev_pw;
+ dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+ }
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->conf->wps_nfc_dh_privkey == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Missing DH params - "
+ "cannot start NFC-triggered connection");
+ return -1;
+ }
+
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - "
+ "cannot start NFC-triggered connection", dev_pw_id);
+ return -1;
+ }
+
+ dh5_free(wps->dh_ctx);
+ wpabuf_free(wps->dh_pubkey);
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+ wps->dh_ctx = NULL;
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key");
+ return -1;
+ }
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+ if (wps->dh_ctx == NULL) {
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context");
+ return -1;
+ }
+
+ if (dev_pw) {
+ wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+ wpabuf_head(dev_pw),
+ wpabuf_len(dev_pw));
+ }
+ return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
+ dev_pw ? pw : NULL,
+ p2p_group, dev_pw_id, peer_pubkey_hash,
+ ssid, ssid_len, freq);
+}
+
+
+static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
+ struct wps_parse_attr *attr)
+{
+ wpa_s->wps_ap_channel = 0;
+
+ /*
+ * Disable existing networks temporarily to allow the newly learned
+ * credential to be preferred. Enable the temporarily disabled networks
+ * after 10 seconds.
+ */
+ wpas_wps_temp_disable(wpa_s, NULL);
+ eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+ NULL);
+
+ if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
+ return -1;
+
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+ return 0;
+
+ if (!wpa_s->wps_ap_channel && attr->ap_channel) {
+ wpa_s->wps_ap_channel = WPA_GET_BE16(attr->ap_channel);
+ wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP Channel %d",
+ wpa_s->wps_ap_channel);
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+ "based on the received credential added");
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ if (wpa_s->wps_ap_channel) {
+ u16 chan = wpa_s->wps_ap_channel;
+ int freq = 0;
+
+ if (chan >= 1 && chan <= 13)
+ freq = 2407 + 5 * chan;
+ else if (chan == 14)
+ freq = 2484;
+ else if (chan >= 30)
+ freq = 5000 + 5 * chan;
+
+ if (freq) {
+ wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
+ "AP channel %u -> %u MHz", chan, freq);
+ wpa_s->after_wps = 5;
+ wpa_s->wps_freq = freq;
+ }
+ }
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_WPS_ER
+static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
+ struct wps_parse_attr *attr)
+{
+ return wps_registrar_add_nfc_password_token(
+ wpa_s->wps->registrar, attr->oob_dev_password,
+ attr->oob_dev_password_len);
+}
+#endif /* CONFIG_WPS_ER */
+
+
+static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *wps)
+{
+ struct wps_parse_attr attr;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+ if (wps_parse_msg(wps, &attr)) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+ return -1;
+ }
+
+ if (attr.num_cred)
+ return wpas_wps_use_cred(wpa_s, &attr);
+
+#ifdef CONFIG_WPS_ER
+ if (attr.oob_dev_password)
+ return wpas_wps_add_nfc_password_token(wpa_s, &attr);
+#endif /* CONFIG_WPS_ER */
+
+ wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+ return -1;
+}
+
+
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq)
+{
+ const struct wpabuf *wps = data;
+ struct wpabuf *tmp = NULL;
+ int ret;
+
+ if (wpabuf_len(data) < 4)
+ return -1;
+
+ if (*wpabuf_head_u8(data) != 0x10) {
+ /* Assume this contains full NDEF record */
+ tmp = ndef_parse_wifi(data);
+ if (tmp == NULL) {
+#ifdef CONFIG_P2P
+ tmp = ndef_parse_p2p(data);
+ if (tmp) {
+ ret = wpas_p2p_nfc_tag_process(wpa_s, tmp,
+ forced_freq);
+ wpabuf_free(tmp);
+ return ret;
+ }
+#endif /* CONFIG_P2P */
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+ return -1;
+ }
+ wps = tmp;
+ }
+
+ ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+ wpabuf_free(tmp);
+ return ret;
+}
+
+
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct wpabuf *ret;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+
+ ret = wps_build_nfc_handover_req(wpa_s->wps,
+ wpa_s->conf->wps_nfc_dh_pubkey);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf *
+wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
+ const char *uuid)
+{
+#ifdef CONFIG_WPS_ER
+ struct wpabuf *ret;
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+ struct wps_context *wps = wpa_s->wps;
+
+ if (wps == NULL)
+ return NULL;
+
+ if (uuid == NULL)
+ return NULL;
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return NULL;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
+ if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+ }
+
+ wpas_wps_nfc_clear(wps);
+ wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+ wpas_wps_nfc_clear(wps);
+ return NULL;
+ }
+
+ ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
+ use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+#else /* CONFIG_WPS_ER */
+ return NULL;
+#endif /* CONFIG_WPS_ER */
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid)
+{
+ struct wpabuf *ret;
+ if (!cr)
+ return NULL;
+ ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
+ if (ret)
+ return ret;
+ return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
+}
+
+
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ /* TODO */
+ return -1;
+}
+
+
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ struct wpabuf *wps;
+ int ret = -1;
+ u16 wsc_len;
+ const u8 *pos;
+ struct wpabuf msg;
+ struct wps_parse_attr attr;
+ u16 dev_pw_id;
+ const u8 *bssid = NULL;
+ int freq = 0;
+
+ wps = ndef_parse_wifi(data);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+ if (wpabuf_len(wps) < 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select "
+ "Message");
+ goto out;
+ }
+ pos = wpabuf_head(wps);
+ wsc_len = WPA_GET_BE16(pos);
+ if (wsc_len > wpabuf_len(wps) - 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+ "in Wi-Fi Handover Select Message", wsc_len);
+ goto out;
+ }
+ pos += 2;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: WSC attributes in Wi-Fi Handover Select Message",
+ pos, wsc_len);
+ if (wsc_len < wpabuf_len(wps) - 2) {
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: Ignore extra data after WSC attributes",
+ pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+ }
+
+ wpabuf_set(&msg, pos, wsc_len);
+ ret = wps_parse_msg(&msg, &attr);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+ "Wi-Fi Handover Select Message");
+ goto out;
+ }
+
+ if (attr.oob_dev_password == NULL ||
+ attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+ "included in Wi-Fi Handover Select Message");
+ ret = -1;
+ goto out;
+ }
+
+ if (attr.ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover "
+ "Select Message");
+ ret = -1;
+ goto out;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len);
+
+ if (attr.mac_addr) {
+ bssid = attr.mac_addr;
+ wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR,
+ MAC2STR(bssid));
+ }
+
+ if (attr.rf_bands)
+ wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands);
+
+ if (attr.ap_channel) {
+ u16 chan = WPA_GET_BE16(attr.ap_channel);
+
+ wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan);
+
+ if (chan >= 1 && chan <= 13 &&
+ (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ))
+ freq = 2407 + 5 * chan;
+ else if (chan == 14 &&
+ (attr.rf_bands == NULL ||
+ *attr.rf_bands & WPS_RF_24GHZ))
+ freq = 2484;
+ else if (chan >= 30 &&
+ (attr.rf_bands == NULL ||
+ *attr.rf_bands & WPS_RF_50GHZ))
+ freq = 5000 + 5 * chan;
+
+ if (freq) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: AP indicated channel %u -> %u MHz",
+ chan, freq);
+ }
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+ attr.oob_dev_password, attr.oob_dev_password_len);
+ dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+ WPS_OOB_PUBKEY_HASH_LEN);
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+ "%u in Wi-Fi Handover Select Message", dev_pw_id);
+ ret = -1;
+ goto out;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
+ attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+ ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0,
+ attr.oob_dev_password,
+ attr.ssid, attr.ssid_len, freq);
+
+out:
+ wpabuf_free(wps);
+ return ret;
+}
+
+
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
+ return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
+}
+
+
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct wpabuf *wps;
+ int ret = -1;
+ u16 wsc_len;
+ const u8 *pos;
+ struct wpabuf msg;
+ struct wps_parse_attr attr;
+ u16 dev_pw_id;
+
+ /*
+ * Enrollee/station is always initiator of the NFC connection handover,
+ * so use the request message here to find Enrollee public key hash.
+ */
+ wps = ndef_parse_wifi(req);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+ if (wpabuf_len(wps) < 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+ "Message");
+ goto out;
+ }
+ pos = wpabuf_head(wps);
+ wsc_len = WPA_GET_BE16(pos);
+ if (wsc_len > wpabuf_len(wps) - 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+ "in rt Wi-Fi Handover Request Message", wsc_len);
+ goto out;
+ }
+ pos += 2;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: WSC attributes in Wi-Fi Handover Request Message",
+ pos, wsc_len);
+ if (wsc_len < wpabuf_len(wps) - 2) {
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: Ignore extra data after WSC attributes",
+ pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+ }
+
+ wpabuf_set(&msg, pos, wsc_len);
+ ret = wps_parse_msg(&msg, &attr);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+ "Wi-Fi Handover Request Message");
+ goto out;
+ }
+
+ if (attr.oob_dev_password == NULL ||
+ attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+ "included in Wi-Fi Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ if (attr.uuid_e == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+ "Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+ attr.oob_dev_password, attr.oob_dev_password_len);
+ dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+ WPS_OOB_PUBKEY_HASH_LEN);
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+ "%u in Wi-Fi Handover Request Message", dev_pw_id);
+ ret = -1;
+ goto out;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+ attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+ ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
+ attr.oob_dev_password,
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ NULL, 0, 1);
+
+out:
+ wpabuf_free(wps);
+ return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+ struct os_reltime now;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ if (wpa_s->wps_ap == NULL)
+ return;
+
+ os_get_reltime(&now);
+
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+
+ wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
+ "tries=%d last_attempt=%d sec ago blacklist=%d",
+ (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
+ ap->last_attempt.sec > 0 ?
+ (int) now.sec - (int) ap->last_attempt.sec : -1,
+ e ? e->count : 0);
+ }
+}
+
+
+static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->wps_ap == NULL)
+ return NULL;
+
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0)
+ return ap;
+ }
+
+ return NULL;
+}
+
+
+static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ struct wpabuf *wps;
+ enum wps_ap_info_type type;
+ struct wps_ap_info *ap;
+ int r;
+
+ if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
+ return;
+
+ wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+ if (wps == NULL)
+ return;
+
+ r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
+ if (r == 2)
+ type = WPS_AP_SEL_REG_OUR;
+ else if (r == 1)
+ type = WPS_AP_SEL_REG;
+ else
+ type = WPS_AP_NOT_SEL_REG;
+
+ wpabuf_free(wps);
+
+ ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
+ if (ap) {
+ if (ap->type != type) {
+ wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
+ " changed type %d -> %d",
+ MAC2STR(res->bssid), ap->type, type);
+ ap->type = type;
+ if (type != WPS_AP_NOT_SEL_REG)
+ wpa_blacklist_del(wpa_s, ap->bssid);
+ }
+ return;
+ }
+
+ ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
+ sizeof(struct wps_ap_info));
+ if (ap == NULL)
+ return;
+
+ wpa_s->wps_ap = ap;
+ ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
+ wpa_s->num_wps_ap++;
+
+ os_memset(ap, 0, sizeof(*ap));
+ os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
+ ap->type = type;
+ wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
+ MAC2STR(ap->bssid), ap->type);
+}
+
+
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ size_t i;
+
+ for (i = 0; i < scan_res->num; i++)
+ wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
+
+ wpas_wps_dump_ap_info(wpa_s);
+}
+
+
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wps_ap_info *ap;
+
+ wpa_s->after_wps = 0;
+
+ if (!wpa_s->wps_ap_iter)
+ return;
+ ap = wpas_wps_get_ap_info(wpa_s, bssid);
+ if (ap == NULL)
+ return;
+ ap->tries++;
+ os_get_reltime(&ap->last_attempt);
+}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index b38c091..86e9d09 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -1,21 +1,15 @@
/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WPS_SUPPLICANT_H
#define WPS_SUPPLICANT_H
-struct wpa_scan_res;
+struct wpa_scan_results;
#ifdef CONFIG_WPS
@@ -40,14 +34,12 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin, int p2p_group, u16 dev_pw_id);
int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
- char *path, char *method, char *name);
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin, struct wps_new_ap_settings *settings);
int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, struct wpa_scan_res *bss);
+ struct wpa_ssid *ssid, struct wpa_bss *bss);
int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, struct wpa_scan_res *bss);
+ struct wpa_ssid *ssid, struct wpa_bss *bss);
int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_ssid *ssid);
void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
@@ -65,9 +57,37 @@ int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
int id);
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings);
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *uuid);
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
-int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str);
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ const u8 *bssid,
+ const struct wpabuf *dev_pw, u16 dev_pw_id,
+ int p2p_group, const u8 *peer_pubkey_hash,
+ const u8 *ssid, size_t ssid_len, int freq);
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
#else /* CONFIG_WPS */
@@ -92,14 +112,14 @@ static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_scan_res *bss)
+ struct wpa_bss *bss)
{
return -1;
}
static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_scan_res *bss)
+ struct wpa_bss *bss)
{
return 0;
}
@@ -120,6 +140,16 @@ static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
return 0;
}
+static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+}
+
+static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_SUPPLICANT_H */
diff --git a/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj b/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj
deleted file mode 100644
index 6fea81b..0000000
--- a/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,513 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 45;
- objects = {
-
-/* Begin PBXBuildFile section */
- 881EED0F10DC14EF009E449F /* eap_register.c in Sources */ = {isa = PBXBuildFile; fileRef = 881EED0E10DC14EF009E449F /* eap_register.c */; };
- 8853CB17109F385C00358CEF /* libpcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB16109F385C00358CEF /* libpcap.dylib */; };
- 8853CB1B109F389800358CEF /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB1A109F389800358CEF /* libcrypto.dylib */; };
- 8853CB1F109F38BD00358CEF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB1E109F38BD00358CEF /* CoreFoundation.framework */; };
- 8853CB2E109F3A3900358CEF /* scan_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CB2D109F3A3900358CEF /* scan_helpers.c */; };
- 8853CB32109F3A9400358CEF /* wpa_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CB31109F3A9400358CEF /* wpa_common.c */; };
- 8853CB36109F3AC700358CEF /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CB35109F3AC700358CEF /* md5.c */; };
- 8853CB3C109F3B5800358CEF /* Apple80211.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CB3B109F3B5800358CEF /* Apple80211.framework */; };
- 8853CBFB109F4C6E00358CEF /* eap_gtc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBEC109F4C6E00358CEF /* eap_gtc.c */; };
- 8853CBFC109F4C6E00358CEF /* eap_leap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBED109F4C6E00358CEF /* eap_leap.c */; };
- 8853CBFD109F4C6E00358CEF /* eap_md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBEE109F4C6E00358CEF /* eap_md5.c */; };
- 8853CBFE109F4C6E00358CEF /* eap_methods.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBEF109F4C6E00358CEF /* eap_methods.c */; };
- 8853CBFF109F4C6E00358CEF /* eap_mschapv2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF0109F4C6E00358CEF /* eap_mschapv2.c */; };
- 8853CC00109F4C6E00358CEF /* eap_otp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF1109F4C6E00358CEF /* eap_otp.c */; };
- 8853CC01109F4C6E00358CEF /* eap_peap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF2109F4C6E00358CEF /* eap_peap.c */; };
- 8853CC02109F4C6E00358CEF /* eap_tls_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF3109F4C6E00358CEF /* eap_tls_common.c */; };
- 8853CC03109F4C6E00358CEF /* eap_tls.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF4109F4C6E00358CEF /* eap_tls.c */; };
- 8853CC04109F4C6E00358CEF /* eap_tnc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF5109F4C6E00358CEF /* eap_tnc.c */; };
- 8853CC05109F4C6E00358CEF /* eap_ttls.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF6109F4C6E00358CEF /* eap_ttls.c */; };
- 8853CC06109F4C6E00358CEF /* eap_wsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF7109F4C6E00358CEF /* eap_wsc.c */; };
- 8853CC07109F4C6E00358CEF /* eap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF8109F4C6E00358CEF /* eap.c */; };
- 8853CC08109F4C6E00358CEF /* mschapv2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBF9109F4C6E00358CEF /* mschapv2.c */; };
- 8853CC09109F4C6E00358CEF /* tncc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CBFA109F4C6E00358CEF /* tncc.c */; };
- 8853CC0E109F4CA100358CEF /* ctrl_iface_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC0C109F4CA100358CEF /* ctrl_iface_unix.c */; };
- 8853CC0F109F4CA100358CEF /* ctrl_iface.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC0D109F4CA100358CEF /* ctrl_iface.c */; };
- 8853CC11109F4CC800358CEF /* eapol_supp_sm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC10109F4CC800358CEF /* eapol_supp_sm.c */; };
- 8853CC18109F4D0800358CEF /* chap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC14109F4D0800358CEF /* chap.c */; };
- 8853CC19109F4D0800358CEF /* eap_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC15109F4D0800358CEF /* eap_common.c */; };
- 8853CC1A109F4D0800358CEF /* eap_peap_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC16109F4D0800358CEF /* eap_peap_common.c */; };
- 8853CC1B109F4D0800358CEF /* eap_wsc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC17109F4D0800358CEF /* eap_wsc_common.c */; };
- 8853CC26109F4D3500358CEF /* wps_attr_build.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC1E109F4D3500358CEF /* wps_attr_build.c */; };
- 8853CC27109F4D3500358CEF /* wps_attr_parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC1F109F4D3500358CEF /* wps_attr_parse.c */; };
- 8853CC28109F4D3500358CEF /* wps_attr_process.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC20109F4D3500358CEF /* wps_attr_process.c */; };
- 8853CC29109F4D3500358CEF /* wps_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC21109F4D3500358CEF /* wps_common.c */; };
- 8853CC2A109F4D3500358CEF /* wps_dev_attr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC22109F4D3500358CEF /* wps_dev_attr.c */; };
- 8853CC2B109F4D3500358CEF /* wps_enrollee.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC23109F4D3500358CEF /* wps_enrollee.c */; };
- 8853CC2C109F4D3500358CEF /* wps_registrar.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC24109F4D3500358CEF /* wps_registrar.c */; };
- 8853CC2D109F4D3500358CEF /* wps.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC25109F4D3500358CEF /* wps.c */; };
- 8853CC34109F4DE200358CEF /* ms_funcs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC32109F4DE200358CEF /* ms_funcs.c */; };
- 8853CC35109F4DE200358CEF /* tls_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC33109F4DE200358CEF /* tls_openssl.c */; };
- 8853CC3C109F4E1D00358CEF /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8853CC3B109F4E1D00358CEF /* libssl.dylib */; };
- 8853CC40109F4E3A00358CEF /* wps_supplicant.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC3F109F4E3A00358CEF /* wps_supplicant.c */; };
- 8853CC44109F4E6200358CEF /* uuid.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC43109F4E6200358CEF /* uuid.c */; };
- 8853CC48109F4E8700358CEF /* ieee802_11_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC47109F4E8700358CEF /* ieee802_11_common.c */; };
- 8853CC4E109F4ED500358CEF /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC4C109F4ED500358CEF /* sha256.c */; };
- 8853CC53109F4F3500358CEF /* aes-cbc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC51109F4F3500358CEF /* aes-cbc.c */; };
- 8853CC54109F4F3500358CEF /* sha1-tlsprf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8853CC52109F4F3500358CEF /* sha1-tlsprf.c */; };
- 88950831109F2FAB004FB35D /* blacklist.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950828109F2FAB004FB35D /* blacklist.c */; };
- 88950832109F2FAB004FB35D /* config_file.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950829109F2FAB004FB35D /* config_file.c */; };
- 88950833109F2FAB004FB35D /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082A109F2FAB004FB35D /* config.c */; };
- 88950834109F2FAB004FB35D /* events.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082B109F2FAB004FB35D /* events.c */; };
- 88950835109F2FAB004FB35D /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082C109F2FAB004FB35D /* main.c */; };
- 88950836109F2FAB004FB35D /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082D109F2FAB004FB35D /* notify.c */; };
- 88950837109F2FAB004FB35D /* scan.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082E109F2FAB004FB35D /* scan.c */; };
- 88950838109F2FAB004FB35D /* wpa_supplicant.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895082F109F2FAB004FB35D /* wpa_supplicant.c */; };
- 88950839109F2FAB004FB35D /* wpas_glue.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950830109F2FAB004FB35D /* wpas_glue.c */; };
- 88950840109F301A004FB35D /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083A109F301A004FB35D /* base64.c */; };
- 88950841109F301A004FB35D /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083B109F301A004FB35D /* common.c */; };
- 88950842109F301A004FB35D /* eloop.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083C109F301A004FB35D /* eloop.c */; };
- 88950843109F301A004FB35D /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083D109F301A004FB35D /* os_unix.c */; };
- 88950844109F301A004FB35D /* wpa_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083E109F301A004FB35D /* wpa_debug.c */; };
- 88950845109F301A004FB35D /* wpabuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895083F109F301A004FB35D /* wpabuf.c */; };
- 88950864109F32D1004FB35D /* peerkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895085F109F32D1004FB35D /* peerkey.c */; };
- 88950865109F32D1004FB35D /* pmksa_cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950860109F32D1004FB35D /* pmksa_cache.c */; };
- 88950866109F32D1004FB35D /* preauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950861109F32D1004FB35D /* preauth.c */; };
- 88950867109F32D1004FB35D /* wpa_ie.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950862109F32D1004FB35D /* wpa_ie.c */; };
- 88950868109F32D1004FB35D /* wpa.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950863109F32D1004FB35D /* wpa.c */; };
- 8895086C109F3316004FB35D /* l2_packet_freebsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086B109F3316004FB35D /* l2_packet_freebsd.c */; };
- 88950871109F3367004FB35D /* aes-unwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086D109F3367004FB35D /* aes-unwrap.c */; };
- 88950872109F3367004FB35D /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086E109F3367004FB35D /* crypto_openssl.c */; };
- 88950873109F3367004FB35D /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8895086F109F3367004FB35D /* sha1-pbkdf2.c */; };
- 88950874109F3367004FB35D /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950870109F3367004FB35D /* sha1.c */; };
- 88950885109F3538004FB35D /* driver_osx.m in Sources */ = {isa = PBXBuildFile; fileRef = 88950883109F3538004FB35D /* driver_osx.m */; };
- 88950886109F3538004FB35D /* drivers.c in Sources */ = {isa = PBXBuildFile; fileRef = 88950884109F3538004FB35D /* drivers.c */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 8DD76FAF0486AB0100D96B5E /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/share/man/man1/;
- dstSubfolderSpec = 0;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 881EED0E10DC14EF009E449F /* eap_register.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_register.c; path = ../eap_register.c; sourceTree = SOURCE_ROOT; };
- 8853CB16109F385C00358CEF /* libpcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcap.dylib; path = usr/lib/libpcap.dylib; sourceTree = SDKROOT; };
- 8853CB1A109F389800358CEF /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; };
- 8853CB1E109F38BD00358CEF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
- 8853CB2D109F3A3900358CEF /* scan_helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scan_helpers.c; path = ../../src/drivers/scan_helpers.c; sourceTree = SOURCE_ROOT; };
- 8853CB31109F3A9400358CEF /* wpa_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_common.c; path = ../../src/common/wpa_common.c; sourceTree = SOURCE_ROOT; };
- 8853CB35109F3AC700358CEF /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../../src/crypto/md5.c; sourceTree = SOURCE_ROOT; };
- 8853CB3B109F3B5800358CEF /* Apple80211.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Apple80211.framework; path = /System/Library/PrivateFrameworks/Apple80211.framework; sourceTree = "<absolute>"; };
- 8853CBEC109F4C6E00358CEF /* eap_gtc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_gtc.c; path = ../../src/eap_peer/eap_gtc.c; sourceTree = SOURCE_ROOT; };
- 8853CBED109F4C6E00358CEF /* eap_leap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_leap.c; path = ../../src/eap_peer/eap_leap.c; sourceTree = SOURCE_ROOT; };
- 8853CBEE109F4C6E00358CEF /* eap_md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_md5.c; path = ../../src/eap_peer/eap_md5.c; sourceTree = SOURCE_ROOT; };
- 8853CBEF109F4C6E00358CEF /* eap_methods.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_methods.c; path = ../../src/eap_peer/eap_methods.c; sourceTree = SOURCE_ROOT; };
- 8853CBF0109F4C6E00358CEF /* eap_mschapv2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_mschapv2.c; path = ../../src/eap_peer/eap_mschapv2.c; sourceTree = SOURCE_ROOT; };
- 8853CBF1109F4C6E00358CEF /* eap_otp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_otp.c; path = ../../src/eap_peer/eap_otp.c; sourceTree = SOURCE_ROOT; };
- 8853CBF2109F4C6E00358CEF /* eap_peap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_peap.c; path = ../../src/eap_peer/eap_peap.c; sourceTree = SOURCE_ROOT; };
- 8853CBF3109F4C6E00358CEF /* eap_tls_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_tls_common.c; path = ../../src/eap_peer/eap_tls_common.c; sourceTree = SOURCE_ROOT; };
- 8853CBF4109F4C6E00358CEF /* eap_tls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_tls.c; path = ../../src/eap_peer/eap_tls.c; sourceTree = SOURCE_ROOT; };
- 8853CBF5109F4C6E00358CEF /* eap_tnc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_tnc.c; path = ../../src/eap_peer/eap_tnc.c; sourceTree = SOURCE_ROOT; };
- 8853CBF6109F4C6E00358CEF /* eap_ttls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_ttls.c; path = ../../src/eap_peer/eap_ttls.c; sourceTree = SOURCE_ROOT; };
- 8853CBF7109F4C6E00358CEF /* eap_wsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_wsc.c; path = ../../src/eap_peer/eap_wsc.c; sourceTree = SOURCE_ROOT; };
- 8853CBF8109F4C6E00358CEF /* eap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap.c; path = ../../src/eap_peer/eap.c; sourceTree = SOURCE_ROOT; };
- 8853CBF9109F4C6E00358CEF /* mschapv2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mschapv2.c; path = ../../src/eap_peer/mschapv2.c; sourceTree = SOURCE_ROOT; };
- 8853CBFA109F4C6E00358CEF /* tncc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tncc.c; path = ../../src/eap_peer/tncc.c; sourceTree = SOURCE_ROOT; };
- 8853CC0C109F4CA100358CEF /* ctrl_iface_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctrl_iface_unix.c; path = ../ctrl_iface_unix.c; sourceTree = SOURCE_ROOT; };
- 8853CC0D109F4CA100358CEF /* ctrl_iface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctrl_iface.c; path = ../ctrl_iface.c; sourceTree = SOURCE_ROOT; };
- 8853CC10109F4CC800358CEF /* eapol_supp_sm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eapol_supp_sm.c; path = ../../src/eapol_supp/eapol_supp_sm.c; sourceTree = SOURCE_ROOT; };
- 8853CC14109F4D0800358CEF /* chap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = chap.c; path = ../../src/eap_common/chap.c; sourceTree = SOURCE_ROOT; };
- 8853CC15109F4D0800358CEF /* eap_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_common.c; path = ../../src/eap_common/eap_common.c; sourceTree = SOURCE_ROOT; };
- 8853CC16109F4D0800358CEF /* eap_peap_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_peap_common.c; path = ../../src/eap_common/eap_peap_common.c; sourceTree = SOURCE_ROOT; };
- 8853CC17109F4D0800358CEF /* eap_wsc_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eap_wsc_common.c; path = ../../src/eap_common/eap_wsc_common.c; sourceTree = SOURCE_ROOT; };
- 8853CC1E109F4D3500358CEF /* wps_attr_build.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_attr_build.c; path = ../../src/wps/wps_attr_build.c; sourceTree = SOURCE_ROOT; };
- 8853CC1F109F4D3500358CEF /* wps_attr_parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_attr_parse.c; path = ../../src/wps/wps_attr_parse.c; sourceTree = SOURCE_ROOT; };
- 8853CC20109F4D3500358CEF /* wps_attr_process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_attr_process.c; path = ../../src/wps/wps_attr_process.c; sourceTree = SOURCE_ROOT; };
- 8853CC21109F4D3500358CEF /* wps_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_common.c; path = ../../src/wps/wps_common.c; sourceTree = SOURCE_ROOT; };
- 8853CC22109F4D3500358CEF /* wps_dev_attr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_dev_attr.c; path = ../../src/wps/wps_dev_attr.c; sourceTree = SOURCE_ROOT; };
- 8853CC23109F4D3500358CEF /* wps_enrollee.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_enrollee.c; path = ../../src/wps/wps_enrollee.c; sourceTree = SOURCE_ROOT; };
- 8853CC24109F4D3500358CEF /* wps_registrar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_registrar.c; path = ../../src/wps/wps_registrar.c; sourceTree = SOURCE_ROOT; };
- 8853CC25109F4D3500358CEF /* wps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps.c; path = ../../src/wps/wps.c; sourceTree = SOURCE_ROOT; };
- 8853CC32109F4DE200358CEF /* ms_funcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ms_funcs.c; path = ../../src/crypto/ms_funcs.c; sourceTree = SOURCE_ROOT; };
- 8853CC33109F4DE200358CEF /* tls_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tls_openssl.c; path = ../../src/crypto/tls_openssl.c; sourceTree = SOURCE_ROOT; };
- 8853CC3B109F4E1D00358CEF /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = usr/lib/libssl.dylib; sourceTree = SDKROOT; };
- 8853CC3F109F4E3A00358CEF /* wps_supplicant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wps_supplicant.c; path = ../wps_supplicant.c; sourceTree = SOURCE_ROOT; };
- 8853CC43109F4E6200358CEF /* uuid.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uuid.c; path = ../../src/utils/uuid.c; sourceTree = SOURCE_ROOT; };
- 8853CC47109F4E8700358CEF /* ieee802_11_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee802_11_common.c; path = ../../src/common/ieee802_11_common.c; sourceTree = SOURCE_ROOT; };
- 8853CC4C109F4ED500358CEF /* sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sha256.c; path = ../../src/crypto/sha256.c; sourceTree = SOURCE_ROOT; };
- 8853CC51109F4F3500358CEF /* aes-cbc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "aes-cbc.c"; path = "../../src/crypto/aes-cbc.c"; sourceTree = SOURCE_ROOT; };
- 8853CC52109F4F3500358CEF /* sha1-tlsprf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "sha1-tlsprf.c"; path = "../../src/crypto/sha1-tlsprf.c"; sourceTree = SOURCE_ROOT; };
- 88950828109F2FAB004FB35D /* blacklist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blacklist.c; path = ../../wpa_supplicant/blacklist.c; sourceTree = SOURCE_ROOT; };
- 88950829109F2FAB004FB35D /* config_file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config_file.c; path = ../../wpa_supplicant/config_file.c; sourceTree = SOURCE_ROOT; };
- 8895082A109F2FAB004FB35D /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config.c; path = ../../wpa_supplicant/config.c; sourceTree = SOURCE_ROOT; };
- 8895082B109F2FAB004FB35D /* events.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = events.c; path = ../../wpa_supplicant/events.c; sourceTree = SOURCE_ROOT; };
- 8895082C109F2FAB004FB35D /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../../wpa_supplicant/main.c; sourceTree = SOURCE_ROOT; };
- 8895082D109F2FAB004FB35D /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = ../../wpa_supplicant/notify.c; sourceTree = SOURCE_ROOT; };
- 8895082E109F2FAB004FB35D /* scan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scan.c; path = ../../wpa_supplicant/scan.c; sourceTree = SOURCE_ROOT; };
- 8895082F109F2FAB004FB35D /* wpa_supplicant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_supplicant.c; path = ../../wpa_supplicant/wpa_supplicant.c; sourceTree = SOURCE_ROOT; };
- 88950830109F2FAB004FB35D /* wpas_glue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpas_glue.c; path = ../../wpa_supplicant/wpas_glue.c; sourceTree = SOURCE_ROOT; };
- 8895083A109F301A004FB35D /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = base64.c; path = ../../src/utils/base64.c; sourceTree = SOURCE_ROOT; };
- 8895083B109F301A004FB35D /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common.c; path = ../../src/utils/common.c; sourceTree = SOURCE_ROOT; };
- 8895083C109F301A004FB35D /* eloop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eloop.c; path = ../../src/utils/eloop.c; sourceTree = SOURCE_ROOT; };
- 8895083D109F301A004FB35D /* os_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_unix.c; path = ../../src/utils/os_unix.c; sourceTree = SOURCE_ROOT; };
- 8895083E109F301A004FB35D /* wpa_debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_debug.c; path = ../../src/utils/wpa_debug.c; sourceTree = SOURCE_ROOT; };
- 8895083F109F301A004FB35D /* wpabuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpabuf.c; path = ../../src/utils/wpabuf.c; sourceTree = SOURCE_ROOT; };
- 8895085F109F32D1004FB35D /* peerkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = peerkey.c; path = ../../src/rsn_supp/peerkey.c; sourceTree = SOURCE_ROOT; };
- 88950860109F32D1004FB35D /* pmksa_cache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pmksa_cache.c; path = ../../src/rsn_supp/pmksa_cache.c; sourceTree = SOURCE_ROOT; };
- 88950861109F32D1004FB35D /* preauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = preauth.c; path = ../../src/rsn_supp/preauth.c; sourceTree = SOURCE_ROOT; };
- 88950862109F32D1004FB35D /* wpa_ie.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa_ie.c; path = ../../src/rsn_supp/wpa_ie.c; sourceTree = SOURCE_ROOT; };
- 88950863109F32D1004FB35D /* wpa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wpa.c; path = ../../src/rsn_supp/wpa.c; sourceTree = SOURCE_ROOT; };
- 8895086B109F3316004FB35D /* l2_packet_freebsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = l2_packet_freebsd.c; path = ../../src/l2_packet/l2_packet_freebsd.c; sourceTree = SOURCE_ROOT; };
- 8895086D109F3367004FB35D /* aes-unwrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "aes-unwrap.c"; path = "../../src/crypto/aes-unwrap.c"; sourceTree = SOURCE_ROOT; };
- 8895086E109F3367004FB35D /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_openssl.c; path = ../../src/crypto/crypto_openssl.c; sourceTree = SOURCE_ROOT; };
- 8895086F109F3367004FB35D /* sha1-pbkdf2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "sha1-pbkdf2.c"; path = "../../src/crypto/sha1-pbkdf2.c"; sourceTree = SOURCE_ROOT; };
- 88950870109F3367004FB35D /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sha1.c; path = ../../src/crypto/sha1.c; sourceTree = SOURCE_ROOT; };
- 88950883109F3538004FB35D /* driver_osx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = driver_osx.m; path = ../../src/drivers/driver_osx.m; sourceTree = SOURCE_ROOT; };
- 88950884109F3538004FB35D /* drivers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = drivers.c; path = ../../src/drivers/drivers.c; sourceTree = SOURCE_ROOT; };
- 8DD76FB20486AB0100D96B5E /* wpa_supplicant */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wpa_supplicant; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 8DD76FAD0486AB0100D96B5E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 8853CB17109F385C00358CEF /* libpcap.dylib in Frameworks */,
- 8853CB1B109F389800358CEF /* libcrypto.dylib in Frameworks */,
- 8853CB1F109F38BD00358CEF /* CoreFoundation.framework in Frameworks */,
- 8853CB3C109F3B5800358CEF /* Apple80211.framework in Frameworks */,
- 8853CC3C109F4E1D00358CEF /* libssl.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 08FB7794FE84155DC02AAC07 /* wpa_supplicant */ = {
- isa = PBXGroup;
- children = (
- 08FB7795FE84155DC02AAC07 /* Source */,
- C6A0FF2B0290797F04C91782 /* Documentation */,
- 1AB674ADFE9D54B511CA2CBB /* Products */,
- 8853CB16109F385C00358CEF /* libpcap.dylib */,
- 8853CB1A109F389800358CEF /* libcrypto.dylib */,
- 8853CB1E109F38BD00358CEF /* CoreFoundation.framework */,
- 8853CB3B109F3B5800358CEF /* Apple80211.framework */,
- 8853CC3B109F4E1D00358CEF /* libssl.dylib */,
- );
- name = wpa_supplicant;
- sourceTree = "<group>";
- };
- 08FB7795FE84155DC02AAC07 /* Source */ = {
- isa = PBXGroup;
- children = (
- 881EED0E10DC14EF009E449F /* eap_register.c */,
- 8853CC51109F4F3500358CEF /* aes-cbc.c */,
- 8853CC52109F4F3500358CEF /* sha1-tlsprf.c */,
- 8853CC4C109F4ED500358CEF /* sha256.c */,
- 8853CC47109F4E8700358CEF /* ieee802_11_common.c */,
- 8853CC43109F4E6200358CEF /* uuid.c */,
- 8853CC3F109F4E3A00358CEF /* wps_supplicant.c */,
- 8853CC32109F4DE200358CEF /* ms_funcs.c */,
- 8853CC33109F4DE200358CEF /* tls_openssl.c */,
- 8853CC1E109F4D3500358CEF /* wps_attr_build.c */,
- 8853CC1F109F4D3500358CEF /* wps_attr_parse.c */,
- 8853CC20109F4D3500358CEF /* wps_attr_process.c */,
- 8853CC21109F4D3500358CEF /* wps_common.c */,
- 8853CC22109F4D3500358CEF /* wps_dev_attr.c */,
- 8853CC23109F4D3500358CEF /* wps_enrollee.c */,
- 8853CC24109F4D3500358CEF /* wps_registrar.c */,
- 8853CC25109F4D3500358CEF /* wps.c */,
- 8853CC14109F4D0800358CEF /* chap.c */,
- 8853CC15109F4D0800358CEF /* eap_common.c */,
- 8853CC16109F4D0800358CEF /* eap_peap_common.c */,
- 8853CC17109F4D0800358CEF /* eap_wsc_common.c */,
- 8853CC10109F4CC800358CEF /* eapol_supp_sm.c */,
- 8853CC0C109F4CA100358CEF /* ctrl_iface_unix.c */,
- 8853CC0D109F4CA100358CEF /* ctrl_iface.c */,
- 8853CBEC109F4C6E00358CEF /* eap_gtc.c */,
- 8853CBED109F4C6E00358CEF /* eap_leap.c */,
- 8853CBEE109F4C6E00358CEF /* eap_md5.c */,
- 8853CBEF109F4C6E00358CEF /* eap_methods.c */,
- 8853CBF0109F4C6E00358CEF /* eap_mschapv2.c */,
- 8853CBF1109F4C6E00358CEF /* eap_otp.c */,
- 8853CBF2109F4C6E00358CEF /* eap_peap.c */,
- 8853CBF3109F4C6E00358CEF /* eap_tls_common.c */,
- 8853CBF4109F4C6E00358CEF /* eap_tls.c */,
- 8853CBF5109F4C6E00358CEF /* eap_tnc.c */,
- 8853CBF6109F4C6E00358CEF /* eap_ttls.c */,
- 8853CBF7109F4C6E00358CEF /* eap_wsc.c */,
- 8853CBF8109F4C6E00358CEF /* eap.c */,
- 8853CBF9109F4C6E00358CEF /* mschapv2.c */,
- 8853CBFA109F4C6E00358CEF /* tncc.c */,
- 8853CB35109F3AC700358CEF /* md5.c */,
- 8853CB31109F3A9400358CEF /* wpa_common.c */,
- 8853CB2D109F3A3900358CEF /* scan_helpers.c */,
- 88950883109F3538004FB35D /* driver_osx.m */,
- 88950884109F3538004FB35D /* drivers.c */,
- 8895086D109F3367004FB35D /* aes-unwrap.c */,
- 8895086E109F3367004FB35D /* crypto_openssl.c */,
- 8895086F109F3367004FB35D /* sha1-pbkdf2.c */,
- 88950870109F3367004FB35D /* sha1.c */,
- 8895086B109F3316004FB35D /* l2_packet_freebsd.c */,
- 8895085F109F32D1004FB35D /* peerkey.c */,
- 88950860109F32D1004FB35D /* pmksa_cache.c */,
- 88950861109F32D1004FB35D /* preauth.c */,
- 88950862109F32D1004FB35D /* wpa_ie.c */,
- 88950863109F32D1004FB35D /* wpa.c */,
- 8895083A109F301A004FB35D /* base64.c */,
- 8895083B109F301A004FB35D /* common.c */,
- 8895083C109F301A004FB35D /* eloop.c */,
- 8895083D109F301A004FB35D /* os_unix.c */,
- 8895083E109F301A004FB35D /* wpa_debug.c */,
- 8895083F109F301A004FB35D /* wpabuf.c */,
- 88950828109F2FAB004FB35D /* blacklist.c */,
- 88950829109F2FAB004FB35D /* config_file.c */,
- 8895082A109F2FAB004FB35D /* config.c */,
- 8895082B109F2FAB004FB35D /* events.c */,
- 8895082C109F2FAB004FB35D /* main.c */,
- 8895082D109F2FAB004FB35D /* notify.c */,
- 8895082E109F2FAB004FB35D /* scan.c */,
- 8895082F109F2FAB004FB35D /* wpa_supplicant.c */,
- 88950830109F2FAB004FB35D /* wpas_glue.c */,
- );
- name = Source;
- sourceTree = "<group>";
- };
- 1AB674ADFE9D54B511CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- 8DD76FB20486AB0100D96B5E /* wpa_supplicant */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- C6A0FF2B0290797F04C91782 /* Documentation */ = {
- isa = PBXGroup;
- children = (
- );
- name = Documentation;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 8DD76FA90486AB0100D96B5E /* wpa_supplicant */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "wpa_supplicant" */;
- buildPhases = (
- 8DD76FAB0486AB0100D96B5E /* Sources */,
- 8DD76FAD0486AB0100D96B5E /* Frameworks */,
- 8DD76FAF0486AB0100D96B5E /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = wpa_supplicant;
- productInstallPath = "$(HOME)/bin";
- productName = wpa_supplicant;
- productReference = 8DD76FB20486AB0100D96B5E /* wpa_supplicant */;
- productType = "com.apple.product-type.tool";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 08FB7793FE84155DC02AAC07 /* Project object */ = {
- isa = PBXProject;
- buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "wpa_supplicant" */;
- compatibilityVersion = "Xcode 3.1";
- hasScannedForEncodings = 1;
- mainGroup = 08FB7794FE84155DC02AAC07 /* wpa_supplicant */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 8DD76FA90486AB0100D96B5E /* wpa_supplicant */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
- 8DD76FAB0486AB0100D96B5E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 88950831109F2FAB004FB35D /* blacklist.c in Sources */,
- 88950832109F2FAB004FB35D /* config_file.c in Sources */,
- 88950833109F2FAB004FB35D /* config.c in Sources */,
- 88950834109F2FAB004FB35D /* events.c in Sources */,
- 88950835109F2FAB004FB35D /* main.c in Sources */,
- 88950836109F2FAB004FB35D /* notify.c in Sources */,
- 88950837109F2FAB004FB35D /* scan.c in Sources */,
- 88950838109F2FAB004FB35D /* wpa_supplicant.c in Sources */,
- 88950839109F2FAB004FB35D /* wpas_glue.c in Sources */,
- 88950840109F301A004FB35D /* base64.c in Sources */,
- 88950841109F301A004FB35D /* common.c in Sources */,
- 88950842109F301A004FB35D /* eloop.c in Sources */,
- 88950843109F301A004FB35D /* os_unix.c in Sources */,
- 88950844109F301A004FB35D /* wpa_debug.c in Sources */,
- 88950845109F301A004FB35D /* wpabuf.c in Sources */,
- 88950864109F32D1004FB35D /* peerkey.c in Sources */,
- 88950865109F32D1004FB35D /* pmksa_cache.c in Sources */,
- 88950866109F32D1004FB35D /* preauth.c in Sources */,
- 88950867109F32D1004FB35D /* wpa_ie.c in Sources */,
- 88950868109F32D1004FB35D /* wpa.c in Sources */,
- 8895086C109F3316004FB35D /* l2_packet_freebsd.c in Sources */,
- 88950871109F3367004FB35D /* aes-unwrap.c in Sources */,
- 88950872109F3367004FB35D /* crypto_openssl.c in Sources */,
- 88950873109F3367004FB35D /* sha1-pbkdf2.c in Sources */,
- 88950874109F3367004FB35D /* sha1.c in Sources */,
- 88950885109F3538004FB35D /* driver_osx.m in Sources */,
- 88950886109F3538004FB35D /* drivers.c in Sources */,
- 8853CB2E109F3A3900358CEF /* scan_helpers.c in Sources */,
- 8853CB32109F3A9400358CEF /* wpa_common.c in Sources */,
- 8853CB36109F3AC700358CEF /* md5.c in Sources */,
- 8853CBFB109F4C6E00358CEF /* eap_gtc.c in Sources */,
- 8853CBFC109F4C6E00358CEF /* eap_leap.c in Sources */,
- 8853CBFD109F4C6E00358CEF /* eap_md5.c in Sources */,
- 8853CBFE109F4C6E00358CEF /* eap_methods.c in Sources */,
- 8853CBFF109F4C6E00358CEF /* eap_mschapv2.c in Sources */,
- 8853CC00109F4C6E00358CEF /* eap_otp.c in Sources */,
- 8853CC01109F4C6E00358CEF /* eap_peap.c in Sources */,
- 8853CC02109F4C6E00358CEF /* eap_tls_common.c in Sources */,
- 8853CC03109F4C6E00358CEF /* eap_tls.c in Sources */,
- 8853CC04109F4C6E00358CEF /* eap_tnc.c in Sources */,
- 8853CC05109F4C6E00358CEF /* eap_ttls.c in Sources */,
- 8853CC06109F4C6E00358CEF /* eap_wsc.c in Sources */,
- 8853CC07109F4C6E00358CEF /* eap.c in Sources */,
- 8853CC08109F4C6E00358CEF /* mschapv2.c in Sources */,
- 8853CC09109F4C6E00358CEF /* tncc.c in Sources */,
- 8853CC0E109F4CA100358CEF /* ctrl_iface_unix.c in Sources */,
- 8853CC0F109F4CA100358CEF /* ctrl_iface.c in Sources */,
- 8853CC11109F4CC800358CEF /* eapol_supp_sm.c in Sources */,
- 8853CC18109F4D0800358CEF /* chap.c in Sources */,
- 8853CC19109F4D0800358CEF /* eap_common.c in Sources */,
- 8853CC1A109F4D0800358CEF /* eap_peap_common.c in Sources */,
- 8853CC1B109F4D0800358CEF /* eap_wsc_common.c in Sources */,
- 8853CC26109F4D3500358CEF /* wps_attr_build.c in Sources */,
- 8853CC27109F4D3500358CEF /* wps_attr_parse.c in Sources */,
- 8853CC28109F4D3500358CEF /* wps_attr_process.c in Sources */,
- 8853CC29109F4D3500358CEF /* wps_common.c in Sources */,
- 8853CC2A109F4D3500358CEF /* wps_dev_attr.c in Sources */,
- 8853CC2B109F4D3500358CEF /* wps_enrollee.c in Sources */,
- 8853CC2C109F4D3500358CEF /* wps_registrar.c in Sources */,
- 8853CC2D109F4D3500358CEF /* wps.c in Sources */,
- 8853CC34109F4DE200358CEF /* ms_funcs.c in Sources */,
- 8853CC35109F4DE200358CEF /* tls_openssl.c in Sources */,
- 8853CC40109F4E3A00358CEF /* wps_supplicant.c in Sources */,
- 8853CC44109F4E6200358CEF /* uuid.c in Sources */,
- 8853CC48109F4E8700358CEF /* ieee802_11_common.c in Sources */,
- 8853CC4E109F4ED500358CEF /* sha256.c in Sources */,
- 8853CC53109F4F3500358CEF /* aes-cbc.c in Sources */,
- 8853CC54109F4F3500358CEF /* sha1-tlsprf.c in Sources */,
- 881EED0F10DC14EF009E449F /* eap_register.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 1DEB928608733DD80010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- COPY_PHASE_STRIP = NO;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
- );
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
- GCC_MODEL_TUNING = G5;
- GCC_OPTIMIZATION_LEVEL = 0;
- INSTALL_PATH = /usr/local/bin;
- PRODUCT_NAME = wpa_supplicant;
- };
- name = Debug;
- };
- 1DEB928708733DD80010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
- );
- GCC_MODEL_TUNING = G5;
- INSTALL_PATH = /usr/local/bin;
- PRODUCT_NAME = wpa_supplicant;
- };
- name = Release;
- };
- 1DEB928A08733DD80010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- FRAMEWORK_SEARCH_PATHS = /System/Library/PrivateFrameworks;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- ../../src,
- ../../src/utils,
- );
- ONLY_ACTIVE_ARCH = YES;
- OTHER_CFLAGS = "-DCONFIG_XCODE_DEFAULTS";
- PREBINDING = NO;
- PRELINK_LIBS = "";
- RUN_CLANG_STATIC_ANALYZER = YES;
- SDKROOT = macosx10.6;
- };
- name = Debug;
- };
- 1DEB928B08733DD80010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- FRAMEWORK_SEARCH_PATHS = /System/Library/PrivateFrameworks;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- ../../src,
- ../../src/utils,
- );
- OTHER_CFLAGS = "-DCONFIG_XCODE_DEFAULTS";
- PREBINDING = NO;
- SDKROOT = macosx10.6;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "wpa_supplicant" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB928608733DD80010E9CD /* Debug */,
- 1DEB928708733DD80010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "wpa_supplicant" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB928A08733DD80010E9CD /* Debug */,
- 1DEB928B08733DD80010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
-}