aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2012-08-29 16:22:06 -0700
committerDmitry Shmidt <dimitrysh@google.com>2012-09-04 17:24:09 -0700
commit61d9df3e62aaa0e87ad05452fcb95142159a17b6 (patch)
tree192ecb010484c58cdec7d39086d64723063268ae
parent4b86ea55603eded752b5773179884a35e74e1a89 (diff)
downloadandroid_external_wpa_supplicant_8-61d9df3e62aaa0e87ad05452fcb95142159a17b6.tar.gz
android_external_wpa_supplicant_8-61d9df3e62aaa0e87ad05452fcb95142159a17b6.tar.bz2
android_external_wpa_supplicant_8-61d9df3e62aaa0e87ad05452fcb95142159a17b6.zip
wpa_supplicant: Update to 29-Aug-2012 TOT
commit 6ffdc2f7bd496ace7a46e055f9714e7db4b1f722 Author: Jouni Malinen <jouni@qca.qualcomm.com> Date: Fri Mar 2 22:31:04 2012 +0200 WFD: Add preliminary WSD request processing and response This commit does not yet address support for different device roles, i.e., the same set of subelements are returned regardless of which role was indicated in the request. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com> Change-Id: I9d63acce719b982c02e589bb59602382e82988c8 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--hostapd/Android.mk74
-rw-r--r--hostapd/Makefile38
-rw-r--r--hostapd/config_file.c690
-rw-r--r--hostapd/ctrl_iface.c274
-rw-r--r--hostapd/ctrl_iface.h13
-rw-r--r--hostapd/defconfig10
-rw-r--r--hostapd/eap_register.c5
-rw-r--r--hostapd/hlr_auc_gw.c197
-rw-r--r--hostapd/hlr_auc_gw.txt98
-rw-r--r--hostapd/hostapd.conf156
-rw-r--r--hostapd/hostapd_cli.c3
-rw-r--r--hostapd/main.c87
-rw-r--r--src/ap/accounting.c109
-rw-r--r--src/ap/accounting.h1
-rw-r--r--src/ap/ap_config.c17
-rw-r--r--src/ap/ap_config.h71
-rw-r--r--src/ap/ap_drv_ops.c36
-rw-r--r--src/ap/ap_drv_ops.h4
-rw-r--r--src/ap/ap_list.c20
-rw-r--r--src/ap/beacon.c30
-rw-r--r--src/ap/drv_callbacks.c213
-rw-r--r--src/ap/gas_serv.c497
-rw-r--r--src/ap/gas_serv.h22
-rw-r--r--src/ap/hostapd.c312
-rw-r--r--src/ap/hostapd.h29
-rw-r--r--src/ap/hs20.c31
-rw-r--r--src/ap/hs20.h16
-rw-r--r--src/ap/hw_features.c4
-rw-r--r--src/ap/ieee802_11.c71
-rw-r--r--src/ap/ieee802_11.h2
-rw-r--r--src/ap/ieee802_11_auth.c147
-rw-r--r--src/ap/ieee802_11_auth.h3
-rw-r--r--src/ap/ieee802_11_vht.c38
-rw-r--r--src/ap/ieee802_1x.c231
-rw-r--r--src/ap/ieee802_1x.h41
-rw-r--r--src/ap/sta_info.c9
-rw-r--r--src/ap/sta_info.h5
-rw-r--r--src/ap/utils.c11
-rw-r--r--src/ap/vlan_init.c49
-rw-r--r--src/ap/vlan_util.c177
-rw-r--r--src/ap/vlan_util.h15
-rw-r--r--src/ap/wnm_ap.c258
-rw-r--r--src/ap/wnm_ap.h17
-rw-r--r--src/ap/wpa_auth.c195
-rw-r--r--src/ap/wpa_auth.h13
-rw-r--r--src/ap/wpa_auth_ft.c60
-rw-r--r--src/ap/wpa_auth_glue.c45
-rw-r--r--src/ap/wpa_auth_i.h3
-rw-r--r--src/ap/wpa_auth_ie.c13
-rw-r--r--src/ap/wps_hostapd.c42
-rw-r--r--src/common/defs.h7
-rw-r--r--src/common/eapol_common.h40
-rw-r--r--src/common/gas.c4
-rw-r--r--src/common/gas.h3
-rw-r--r--src/common/ieee802_11_common.c85
-rw-r--r--src/common/ieee802_11_common.h17
-rw-r--r--src/common/ieee802_11_defs.h19
-rw-r--r--src/common/wpa_common.c6
-rw-r--r--src/common/wpa_common.h4
-rw-r--r--src/common/wpa_ctrl.c107
-rw-r--r--src/common/wpa_ctrl.h12
-rw-r--r--src/crypto/Makefile3
-rw-r--r--src/crypto/crypto.h26
-rw-r--r--src/crypto/crypto_openssl.c271
-rw-r--r--src/crypto/fips_prf_openssl.c5
-rw-r--r--src/crypto/md5-non-fips.c107
-rw-r--r--src/crypto/md5.h10
-rw-r--r--src/crypto/ms_funcs.c12
-rw-r--r--src/crypto/random.c22
-rw-r--r--src/crypto/sha1-pbkdf2.c6
-rw-r--r--src/crypto/sha1-prf.c66
-rw-r--r--src/crypto/sha1-tlsprf.c9
-rw-r--r--src/crypto/sha1.c53
-rw-r--r--src/crypto/sha1.h2
-rw-r--r--src/crypto/sha256-prf.c64
-rw-r--r--src/crypto/sha256.c77
-rw-r--r--src/crypto/sha256.h8
-rw-r--r--src/crypto/tls.h1
-rw-r--r--src/crypto/tls_openssl.c57
-rw-r--r--src/drivers/android_drv.h2
-rw-r--r--src/drivers/driver.h86
-rw-r--r--src/drivers/driver_atheros.c440
-rw-r--r--src/drivers/driver_bsd.c4
-rw-r--r--src/drivers/driver_common.c1
-rw-r--r--src/drivers/driver_ndis.c2
-rw-r--r--src/drivers/driver_nl80211.c318
-rw-r--r--src/drivers/driver_privsep.c2
-rw-r--r--src/drivers/driver_test.c41
-rw-r--r--src/drivers/driver_wext.c39
-rw-r--r--src/drivers/driver_wext.h1
-rw-r--r--src/drivers/drivers.mak24
-rw-r--r--src/drivers/drivers.mk25
-rw-r--r--src/drivers/linux_ioctl.c5
-rw-r--r--src/drivers/nl80211_copy.h62
-rw-r--r--src/eap_common/eap_common.c49
-rw-r--r--src/eap_common/eap_common.h3
-rw-r--r--src/eap_common/eap_defs.h6
-rw-r--r--src/eap_peer/eap.c73
-rw-r--r--src/eap_peer/eap.h3
-rw-r--r--src/eap_peer/eap_config.h3
-rw-r--r--src/eap_peer/eap_fast.c2
-rw-r--r--src/eap_peer/eap_i.h3
-rw-r--r--src/eap_peer/eap_md5.c10
-rw-r--r--src/eap_peer/eap_methods.h1
-rw-r--r--src/eap_peer/eap_mschapv2.c4
-rw-r--r--src/eap_peer/eap_peap.c2
-rw-r--r--src/eap_peer/eap_tls.c73
-rw-r--r--src/eap_peer/eap_tls_common.c56
-rw-r--r--src/eap_peer/eap_tls_common.h10
-rw-r--r--src/eap_peer/eap_ttls.c12
-rw-r--r--src/eap_peer/eap_vendor_test.c2
-rw-r--r--src/eap_peer/mschapv2.c35
-rw-r--r--src/eap_server/eap_methods.h1
-rw-r--r--src/eap_server/eap_server.c11
-rw-r--r--src/eap_server/eap_server_md5.c10
-rw-r--r--src/eap_server/eap_server_tls.c76
-rw-r--r--src/eap_server/eap_server_tls_common.c26
-rw-r--r--src/eap_server/eap_server_tnc.c1
-rw-r--r--src/eap_server/eap_server_ttls.c16
-rw-r--r--src/eap_server/eap_server_vendor_test.c2
-rw-r--r--src/eap_server/eap_sim_db.c8
-rw-r--r--src/eap_server/eap_tls_common.h5
-rw-r--r--src/eapol_auth/eapol_auth_sm.c12
-rw-r--r--src/eapol_auth/eapol_auth_sm.h3
-rw-r--r--src/eapol_supp/eapol_supp_sm.c71
-rw-r--r--src/eapol_supp/eapol_supp_sm.h14
-rw-r--r--src/p2p/p2p.c299
-rw-r--r--src/p2p/p2p.h40
-rw-r--r--src/p2p/p2p_go_neg.c48
-rw-r--r--src/p2p/p2p_group.c231
-rw-r--r--src/p2p/p2p_i.h30
-rw-r--r--src/p2p/p2p_invitation.c58
-rw-r--r--src/p2p/p2p_parse.c11
-rw-r--r--src/p2p/p2p_pd.c59
-rw-r--r--src/p2p/p2p_sd.c57
-rw-r--r--src/radius/radius.c56
-rw-r--r--src/radius/radius.h4
-rw-r--r--src/radius/radius_client.c4
-rw-r--r--src/radius/radius_das.c14
-rw-r--r--src/radius/radius_server.c12
-rw-r--r--src/rsn_supp/peerkey.c23
-rw-r--r--src/rsn_supp/pmksa_cache.c24
-rw-r--r--src/rsn_supp/wpa.c170
-rw-r--r--src/rsn_supp/wpa.h4
-rw-r--r--src/rsn_supp/wpa_ft.c15
-rw-r--r--src/rsn_supp/wpa_ie.c4
-rw-r--r--src/utils/common.c253
-rw-r--r--src/utils/common.h9
-rw-r--r--src/utils/edit.c16
-rw-r--r--src/utils/edit.h2
-rw-r--r--src/utils/edit_readline.c16
-rw-r--r--src/utils/edit_simple.c8
-rw-r--r--src/utils/eloop.c18
-rw-r--r--src/utils/eloop_win.c17
-rw-r--r--src/utils/ext_password.c116
-rw-r--r--src/utils/ext_password.h33
-rw-r--r--src/utils/ext_password_i.h23
-rw-r--r--src/utils/ext_password_test.c90
-rw-r--r--src/utils/os.h27
-rw-r--r--src/utils/wpabuf.c19
-rw-r--r--src/utils/wpabuf.h20
-rw-r--r--src/wps/wps.c8
-rw-r--r--src/wps/wps_enrollee.c10
-rw-r--r--src/wps/wps_registrar.c14
-rw-r--r--wpa_supplicant/Android.mk89
-rw-r--r--wpa_supplicant/Makefile78
-rw-r--r--wpa_supplicant/README-HS20470
-rw-r--r--wpa_supplicant/README-P2P16
-rw-r--r--wpa_supplicant/android.config3
-rw-r--r--wpa_supplicant/ap.c24
-rw-r--r--wpa_supplicant/bgscan_learn.c8
-rw-r--r--wpa_supplicant/config.c305
-rw-r--r--wpa_supplicant/config.h86
-rw-r--r--wpa_supplicant/config_file.c60
-rw-r--r--wpa_supplicant/config_ssid.h24
-rw-r--r--wpa_supplicant/config_winreg.c7
-rw-r--r--wpa_supplicant/ctrl_iface.c260
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c39
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c17
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.c18
-rw-r--r--wpa_supplicant/dbus/dbus_new.c13
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c63
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h3
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c14
-rw-r--r--wpa_supplicant/defconfig11
-rw-r--r--wpa_supplicant/driver_i.h10
-rw-r--r--wpa_supplicant/eap_register.c10
-rw-r--r--wpa_supplicant/eapol_test.c50
-rw-r--r--wpa_supplicant/events.c127
-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/gas_query.c4
-rw-r--r--wpa_supplicant/interworking.c488
-rw-r--r--wpa_supplicant/interworking.h6
-rw-r--r--wpa_supplicant/main.c32
-rw-r--r--wpa_supplicant/p2p_supplicant.c464
-rw-r--r--wpa_supplicant/p2p_supplicant.h13
-rw-r--r--wpa_supplicant/scan.c35
-rw-r--r--wpa_supplicant/sme.c36
-rw-r--r--wpa_supplicant/tests/test_eap_sim_common.c2
-rw-r--r--wpa_supplicant/wifi_display.c251
-rw-r--r--wpa_supplicant/wifi_display.h20
-rw-r--r--wpa_supplicant/wnm_sta.c248
-rw-r--r--wpa_supplicant/wnm_sta.h21
-rw-r--r--wpa_supplicant/wpa_cli.c1682
-rw-r--r--wpa_supplicant/wpa_passphrase.c2
-rw-r--r--wpa_supplicant/wpa_supplicant.c249
-rw-r--r--wpa_supplicant/wpa_supplicant.conf90
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h48
-rw-r--r--wpa_supplicant/wps_supplicant.c162
-rw-r--r--wpa_supplicant/wps_supplicant.h14
217 files changed, 13365 insertions, 3036 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 107f381c..7f1e6e64 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -100,6 +100,7 @@ NEED_RC4=y
NEED_AES=y
NEED_MD5=y
NEED_SHA1=y
+NEED_SHA256=y
OBJS += src/drivers/drivers.c
L_CFLAGS += -DHOSTAPD
@@ -145,6 +146,7 @@ CONFIG_NO_ACCOUNTING=y
else
OBJS += src/radius/radius.c
OBJS += src/radius/radius_client.c
+OBJS += src/radius/radius_das.c
endif
ifdef CONFIG_NO_ACCOUNTING
@@ -157,6 +159,12 @@ ifdef CONFIG_NO_VLAN
L_CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += src/ap/vlan_init.c
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_util.c
+endif
+L_CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@@ -199,10 +207,23 @@ NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_IEEE80211V
+L_CFLAGS += -DCONFIG_IEEE80211V
+OBJS += src/ap/wnm_ap.c
+endif
+
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+endif
+
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
OBJS += $(DRV_AP_OBJS)
@@ -239,6 +260,14 @@ OBJS += src/eap_server/eap_server_tls.c
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+endif
+
ifdef CONFIG_EAP_PEAP
L_CFLAGS += -DEAP_SERVER_PEAP
OBJS += src/eap_server/eap_server_peap.c
@@ -472,6 +501,15 @@ ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
+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
OBJS += src/crypto/tls_openssl.c
@@ -490,10 +528,6 @@ ifeq ($(CONFIG_TLS), gnutls)
ifdef TLS_FUNCS
OBJS += src/crypto/tls_gnutls.c
LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
endif
OBJS += src/crypto/crypto_gnutls.c
HOBJS += src/crypto/crypto_gnutls.c
@@ -555,6 +589,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
@@ -669,14 +706,19 @@ 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
SHA1OBJS += src/crypto/fips_prf_internal.c
endif
endif
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
ifdef NEED_T_PRF
SHA1OBJS += src/crypto/sha1-tprf.c
endif
@@ -715,10 +757,17 @@ endif
endif
ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
OBJS += src/crypto/sha256.c
+endif
+OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
OBJS += src/crypto/sha256-internal.c
endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += src/crypto/sha256-tlsprf.c
+endif
endif
ifdef NEED_DH_GROUPS
@@ -738,6 +787,7 @@ L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
OBJS += src/crypto/random.c
HOBJS += src/crypto/random.c
+HOBJS += src/utils/eloop.c
HOBJS += $(SHA1OBJS)
HOBJS += src/crypto/md5.c
endif
@@ -776,11 +826,27 @@ ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
endif
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+
ifdef CONFIG_P2P_MANAGER
L_CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += src/ap/p2p_hostapd.c
endif
+ifdef CONFIG_HS20
+L_CFLAGS += -DCONFIG_HS20
+OBJS += src/ap/hs20.c
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+L_CFLAGS += -DCONFIG_INTERWORKING
+OBJS += src/common/gas.c
+OBJS += src/ap/gas_serv.c
+endif
+
OBJS += src/drivers/driver_common.c
ifdef CONFIG_NO_STDOUT_DEBUG
diff --git a/hostapd/Makefile b/hostapd/Makefile
index b43aa75a..6809b076 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -123,6 +123,12 @@ ifdef CONFIG_NO_VLAN
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_util.o
+endif
+CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@@ -165,6 +171,11 @@ NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_IEEE80211V
+CFLAGS += -DCONFIG_IEEE80211V
+OBJS += ../src/ap/wnm_ap.o
+endif
+
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
@@ -212,6 +223,14 @@ OBJS += ../src/eap_server/eap_server_tls.o
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+endif
+
ifdef CONFIG_EAP_PEAP
CFLAGS += -DEAP_SERVER_PEAP
OBJS += ../src/eap_server/eap_server_peap.o
@@ -649,14 +668,19 @@ 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
SHA1OBJS += ../src/crypto/fips_prf_internal.o
endif
endif
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -696,7 +720,10 @@ endif
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
OBJS += ../src/crypto/sha256.o
+endif
+OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
OBJS += ../src/crypto/sha256-internal.o
endif
@@ -770,6 +797,12 @@ CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += ../src/ap/p2p_hostapd.o
endif
+ifdef CONFIG_HS20
+CFLAGS += -DCONFIG_HS20
+OBJS += ../src/ap/hs20.o
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
CFLAGS += -DCONFIG_INTERWORKING
OBJS += ../src/common/gas.o
@@ -859,6 +892,11 @@ ifdef TLS_FUNCS
LIBS_n += -lcrypto
endif
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS_h += -lsqlite3
+endif
+
HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
HOBJS += ../src/crypto/aes-encblock.o
ifdef CONFIG_INTERNAL_AES
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index eebbaa68..0a24ec37 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -167,7 +167,7 @@ static int hostapd_config_read_maclist(const char *fname,
if (*pos != '\0')
vlan_id = atoi(pos);
- newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
if (newacl == NULL) {
wpa_printf(MSG_ERROR, "MAC list reallocation failed");
fclose(f);
@@ -475,7 +475,7 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
int ret;
static int server_index = 1;
- nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+ nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
if (nserv == NULL)
return -1;
@@ -567,25 +567,21 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
const char *val)
{
char *secret;
- size_t len;
secret = os_strchr(val, ' ');
if (secret == NULL)
return -1;
secret++;
- len = os_strlen(secret);
if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
return -1;
os_free(bss->radius_das_shared_secret);
- bss->radius_das_shared_secret = os_malloc(len);
+ bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
if (bss->radius_das_shared_secret == NULL)
return -1;
-
- os_memcpy(bss->radius_das_shared_secret, secret, len);
- bss->radius_das_shared_secret_len = len;
+ bss->radius_das_shared_secret_len = os_strlen(secret);
return 0;
}
@@ -673,6 +669,8 @@ static int hostapd_config_parse_cipher(int line, const char *value)
*end = '\0';
if (os_strcmp(start, "CCMP") == 0)
val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
else if (os_strcmp(start, "WEP104") == 0)
@@ -784,8 +782,8 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
if (*ifname == '\0')
return -1;
- bss = os_realloc(conf->bss, (conf->num_bss + 1) *
- sizeof(struct hostapd_bss_config));
+ bss = os_realloc_array(conf->bss, conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config));
if (bss == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"multi-BSS entry");
@@ -909,78 +907,6 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
}
-static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
- char *val)
-{
- int num, v;
- char *pos;
- struct hostapd_wmm_ac_params *ac;
-
- /* skip 'wme_ac_' or 'wmm_ac_' prefix */
- pos = name + 7;
- if (os_strncmp(pos, "be_", 3) == 0) {
- num = 0;
- pos += 3;
- } else if (os_strncmp(pos, "bk_", 3) == 0) {
- num = 1;
- pos += 3;
- } else if (os_strncmp(pos, "vi_", 3) == 0) {
- num = 2;
- pos += 3;
- } else if (os_strncmp(pos, "vo_", 3) == 0) {
- num = 3;
- pos += 3;
- } else {
- wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
- return -1;
- }
-
- ac = &conf->wmm_ac_params[num];
-
- if (os_strcmp(pos, "aifs") == 0) {
- v = atoi(val);
- if (v < 1 || v > 255) {
- wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
- return -1;
- }
- ac->aifs = v;
- } else if (os_strcmp(pos, "cwmin") == 0) {
- v = atoi(val);
- if (v < 0 || v > 12) {
- wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
- return -1;
- }
- ac->cwmin = v;
- } else if (os_strcmp(pos, "cwmax") == 0) {
- v = atoi(val);
- if (v < 0 || v > 12) {
- wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
- return -1;
- }
- ac->cwmax = v;
- } else if (os_strcmp(pos, "txop_limit") == 0) {
- v = atoi(val);
- if (v < 0 || v > 0xffff) {
- wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
- return -1;
- }
- ac->txop_limit = v;
- } else if (os_strcmp(pos, "acm") == 0) {
- v = atoi(val);
- if (v < 0 || v > 1) {
- wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
- return -1;
- }
- ac->admission_control_mandatory = v;
- } else {
- wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211R
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
@@ -1268,10 +1194,10 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
- !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
- "requires CCMP to be enabled, disabling HT "
+ "requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
#endif /* CONFIG_IEEE80211N */
@@ -1288,8 +1214,27 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
"disabled");
bss->wps_state = 0;
}
+
+ if (bss->wps_state && bss->wpa &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+ wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+ "WPA2/CCMP forced WPS to be disabled");
+ bss->wps_state = 0;
+ }
#endif /* CONFIG_WPS2 */
+#ifdef CONFIG_HS20
+ if (bss->hs20 &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+ wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+ "configuration is required for Hotspot 2.0 "
+ "functionality");
+ return -1;
+ }
+#endif /* CONFIG_HS20 */
+
return 0;
}
@@ -1330,9 +1275,9 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
}
len /= 2;
- rc = os_realloc(bss->roaming_consortium,
- sizeof(struct hostapd_roaming_consortium) *
- (bss->roaming_consortium_count + 1));
+ rc = os_realloc_array(bss->roaming_consortium,
+ bss->roaming_consortium_count + 1,
+ sizeof(struct hostapd_roaming_consortium));
if (rc == NULL)
return -1;
@@ -1346,50 +1291,387 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
}
-static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
- int line)
+static int parse_lang_string(struct hostapd_lang_string **array,
+ unsigned int *count, char *pos)
{
char *sep;
size_t clen, nlen;
- struct hostapd_venue_name *vn;
+ struct hostapd_lang_string *ls;
sep = os_strchr(pos, ':');
if (sep == NULL)
- goto fail;
+ return -1;
*sep++ = '\0';
clen = os_strlen(pos);
if (clen < 2)
- goto fail;
+ return -1;
nlen = os_strlen(sep);
if (nlen > 252)
+ return -1;
+
+ ls = os_realloc_array(*array, *count + 1,
+ sizeof(struct hostapd_lang_string));
+ if (ls == NULL)
+ return -1;
+
+ *array = ls;
+ ls = &(*array)[*count];
+ (*count)++;
+
+ os_memset(ls->lang, 0, sizeof(ls->lang));
+ os_memcpy(ls->lang, pos, clen);
+ ls->name_len = nlen;
+ os_memcpy(ls->name, sep, nlen);
+
+ return 0;
+}
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+ line, pos);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ size_t count;
+ char *pos;
+ u8 *info = NULL, *ipos;
+
+ /* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
+
+ count = 1;
+ for (pos = buf; *pos; pos++) {
+ if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
+ goto fail;
+ if (*pos == ';')
+ count++;
+ }
+ if (1 + count * 3 > 0x7f)
goto fail;
- vn = os_realloc(bss->venue_name,
- sizeof(struct hostapd_venue_name) *
- (bss->venue_name_count + 1));
- if (vn == NULL)
+ info = os_zalloc(2 + 3 + count * 3);
+ if (info == NULL)
return -1;
- bss->venue_name = vn;
- vn = &bss->venue_name[bss->venue_name_count];
- bss->venue_name_count++;
+ ipos = info;
+ *ipos++ = 0; /* GUD - Version 1 */
+ *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
+ *ipos++ = 0; /* PLMN List IEI */
+ /* ext(b8) | Length of PLMN List value contents(b7..1) */
+ *ipos++ = 1 + count * 3;
+ *ipos++ = count; /* Number of PLMNs */
+
+ pos = buf;
+ while (pos && *pos) {
+ char *mcc, *mnc;
+ size_t mnc_len;
+
+ mcc = pos;
+ mnc = os_strchr(pos, ',');
+ if (mnc == NULL)
+ goto fail;
+ *mnc++ = '\0';
+ pos = os_strchr(mnc, ';');
+ if (pos)
+ *pos++ = '\0';
+
+ mnc_len = os_strlen(mnc);
+ if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
+ goto fail;
+
+ /* BC coded MCC,MNC */
+ /* MCC digit 2 | MCC digit 1 */
+ *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
+ /* MNC digit 3 | MCC digit 3 */
+ *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
+ (mcc[2] - '0');
+ /* MNC digit 2 | MNC digit 1 */
+ *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
+ }
- os_memset(vn->lang, 0, sizeof(vn->lang));
- os_memcpy(vn->lang, pos, clen);
- vn->name_len = nlen;
- os_memcpy(vn->name, sep, nlen);
+ os_free(bss->anqp_3gpp_cell_net);
+ bss->anqp_3gpp_cell_net = info;
+ bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
+ wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
+ bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
return 0;
fail:
- wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
- line, pos);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
+ line, buf);
+ os_free(info);
return -1;
}
+
+
+static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
+{
+ struct hostapd_nai_realm_data *realm;
+ size_t i, j, len;
+ int *offsets;
+ char *pos, *end, *rpos;
+
+ offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
+ sizeof(int));
+ if (offsets == NULL)
+ return -1;
+
+ for (i = 0; i < bss->nai_realm_count; i++) {
+ realm = &bss->nai_realm_data[i];
+ for (j = 0; j < MAX_NAI_REALMS; j++) {
+ offsets[i * MAX_NAI_REALMS + j] =
+ realm->realm[j] ?
+ realm->realm[j] - realm->realm_buf : -1;
+ }
+ }
+
+ realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
+ sizeof(struct hostapd_nai_realm_data));
+ if (realm == NULL) {
+ os_free(offsets);
+ return -1;
+ }
+ bss->nai_realm_data = realm;
+
+ /* patch the pointers after realloc */
+ for (i = 0; i < bss->nai_realm_count; i++) {
+ realm = &bss->nai_realm_data[i];
+ for (j = 0; j < MAX_NAI_REALMS; j++) {
+ int offs = offsets[i * MAX_NAI_REALMS + j];
+ if (offs >= 0)
+ realm->realm[j] = realm->realm_buf + offs;
+ else
+ realm->realm[j] = NULL;
+ }
+ }
+ os_free(offsets);
+
+ realm = &bss->nai_realm_data[bss->nai_realm_count];
+ os_memset(realm, 0, sizeof(*realm));
+
+ pos = buf;
+ realm->encoding = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ end = os_strchr(pos, ',');
+ if (end) {
+ len = end - pos;
+ *end = '\0';
+ } else {
+ len = os_strlen(pos);
+ }
+
+ if (len > MAX_NAI_REALMLEN) {
+ wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
+ "characters)", (int) len, MAX_NAI_REALMLEN);
+ goto fail;
+ }
+ os_memcpy(realm->realm_buf, pos, len);
+
+ if (end)
+ pos = end + 1;
+ else
+ pos = NULL;
+
+ while (pos && *pos) {
+ struct hostapd_nai_realm_eap *eap;
+
+ if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
+ wpa_printf(MSG_ERROR, "Too many EAP methods");
+ goto fail;
+ }
+
+ eap = &realm->eap_method[realm->eap_method_count];
+ realm->eap_method_count++;
+
+ end = os_strchr(pos, ',');
+ if (end == NULL)
+ end = pos + os_strlen(pos);
+
+ eap->eap_method = atoi(pos);
+ for (;;) {
+ pos = os_strchr(pos, '[');
+ if (pos == NULL || pos > end)
+ break;
+ pos++;
+ if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
+ wpa_printf(MSG_ERROR, "Too many auth params");
+ goto fail;
+ }
+ eap->auth_id[eap->num_auths] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL || pos > end)
+ goto fail;
+ pos++;
+ eap->auth_val[eap->num_auths] = atoi(pos);
+ pos = os_strchr(pos, ']');
+ if (pos == NULL || pos > end)
+ goto fail;
+ pos++;
+ eap->num_auths++;
+ }
+
+ if (*end != ',')
+ break;
+
+ pos = end + 1;
+ }
+
+ /* Split realm list into null terminated realms */
+ rpos = realm->realm_buf;
+ i = 0;
+ while (*rpos) {
+ if (i >= MAX_NAI_REALMS) {
+ wpa_printf(MSG_ERROR, "Too many realms");
+ goto fail;
+ }
+ realm->realm[i++] = rpos;
+ rpos = os_strchr(rpos, ';');
+ if (rpos == NULL)
+ break;
+ *rpos++ = '\0';
+ }
+
+ bss->nai_realm_count++;
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
+ return -1;
+}
+
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ u8 *conn_cap;
+ char *pos;
+
+ if (bss->hs20_connection_capability_len >= 0xfff0)
+ return -1;
+
+ conn_cap = os_realloc(bss->hs20_connection_capability,
+ bss->hs20_connection_capability_len + 4);
+ if (conn_cap == NULL)
+ return -1;
+
+ bss->hs20_connection_capability = conn_cap;
+ conn_cap += bss->hs20_connection_capability_len;
+ pos = buf;
+ conn_cap[0] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ WPA_PUT_LE16(conn_cap + 1, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ conn_cap[3] = atoi(pos);
+ bss->hs20_connection_capability_len += 4;
+
+ return 0;
+}
+
+
+static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ u8 *wan_metrics;
+ char *pos;
+
+ /* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
+
+ wan_metrics = os_zalloc(13);
+ if (wan_metrics == NULL)
+ return -1;
+
+ pos = buf;
+ /* WAN Info */
+ if (hexstr2bin(pos, wan_metrics, 1) < 0)
+ goto fail;
+ pos += 2;
+ if (*pos != ':')
+ goto fail;
+ pos++;
+
+ /* Downlink Speed */
+ WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Uplink Speed */
+ WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Downlink Load */
+ wan_metrics[9] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Uplink Load */
+ wan_metrics[10] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* LMD */
+ WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
+
+ os_free(bss->hs20_wan_metrics);
+ bss->hs20_wan_metrics = wan_metrics;
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
+ line, pos);
+ os_free(wan_metrics);
+ return -1;
+}
+
+
+static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
+ char *pos, int line)
+{
+ if (parse_lang_string(&bss->hs20_oper_friendly_name,
+ &bss->hs20_oper_friendly_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_oper_friendly_name '%s'", line, pos);
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_HS20 */
+
+
#ifdef CONFIG_WPS_NFC
static struct wpabuf * hostapd_parse_bin(const char *buf)
{
@@ -1470,9 +1752,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else {
os_memcpy(bss->ssid.ssid, pos,
bss->ssid.ssid_len);
- bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
bss->ssid.ssid_set = 1;
}
+ } else if (os_strcmp(buf, "ssid2") == 0) {
+ size_t slen;
+ char *str = wpa_config_parse_string(pos, &slen);
+ if (str == NULL || slen < 1 ||
+ slen > HOSTAPD_MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+ "'%s'", line, pos);
+ errors++;
+ } else {
+ os_memcpy(bss->ssid.ssid, str, slen);
+ bss->ssid.ssid_len = slen;
+ bss->ssid.ssid_set = 1;
+ }
+ os_free(str);
} else if (os_strcmp(buf, "macaddr_acl") == 0) {
bss->macaddr_acl = atoi(pos);
if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
@@ -2120,6 +2415,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
"read VLAN file '%s'", line, pos);
errors++;
}
+ } else if (os_strcmp(buf, "vlan_naming") == 0) {
+ bss->ssid.vlan_naming = atoi(pos);
+ if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
+ bss->ssid.vlan_naming < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "naming scheme %d", line,
+ bss->ssid.vlan_naming);
+ errors++;
+ }
#ifdef CONFIG_FULL_DYNAMIC_VLAN
} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
bss->ssid.vlan_tagged_interface = os_strdup(pos);
@@ -2142,7 +2446,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wmm_uapsd = atoi(pos);
} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
os_strncmp(buf, "wmm_ac_", 7) == 0) {
- if (hostapd_config_wmm_ac(conf, buf, pos)) {
+ if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
+ pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
"ac item", line);
errors++;
@@ -2200,8 +2505,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
"vht_capab", line);
errors++;
}
+ } else if (os_strcmp(buf, "require_vht") == 0) {
+ conf->require_vht = atoi(pos);
} else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
- conf->vht_oper_chwidth = atoi(pos);
+ conf->vht_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
+ {
+ conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -2429,6 +2739,92 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "venue_name") == 0) {
if (parse_venue_name(bss, pos, line) < 0)
errors++;
+ } else if (os_strcmp(buf, "network_auth_type") == 0) {
+ u8 auth_type;
+ u16 redirect_url_len;
+ if (hexstr2bin(pos, &auth_type, 1)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "network_auth_type '%s'",
+ line, pos);
+ errors++;
+ return errors;
+ }
+ if (auth_type == 0 || auth_type == 2)
+ redirect_url_len = os_strlen(pos + 2);
+ else
+ redirect_url_len = 0;
+ os_free(bss->network_auth_type);
+ bss->network_auth_type =
+ os_malloc(redirect_url_len + 3 + 1);
+ if (bss->network_auth_type == NULL) {
+ errors++;
+ return errors;
+ }
+ *bss->network_auth_type = auth_type;
+ WPA_PUT_LE16(bss->network_auth_type + 1,
+ redirect_url_len);
+ if (redirect_url_len)
+ os_memcpy(bss->network_auth_type + 3,
+ pos + 2, redirect_url_len);
+ bss->network_auth_type_len = 3 + redirect_url_len;
+ } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
+ if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "ipaddr_type_availability '%s'",
+ line, pos);
+ bss->ipaddr_type_configured = 0;
+ errors++;
+ return errors;
+ }
+ bss->ipaddr_type_configured = 1;
+ } else if (os_strcmp(buf, "domain_name") == 0) {
+ int j, num_domains, domain_len, domain_list_len = 0;
+ char *tok_start, *tok_prev;
+ u8 *domain_list, *domain_ptr;
+
+ domain_list_len = os_strlen(pos) + 1;
+ domain_list = os_malloc(domain_list_len);
+ if (domain_list == NULL) {
+ errors++;
+ return errors;
+ }
+
+ domain_ptr = domain_list;
+ tok_prev = pos;
+ num_domains = 1;
+ while ((tok_prev = os_strchr(tok_prev, ','))) {
+ num_domains++;
+ tok_prev++;
+ }
+ tok_prev = pos;
+ for (j = 0; j < num_domains; j++) {
+ tok_start = os_strchr(tok_prev, ',');
+ if (tok_start) {
+ domain_len = tok_start - tok_prev;
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev,
+ domain_len);
+ domain_ptr += domain_len + 1;
+ tok_prev = ++tok_start;
+ } else {
+ domain_len = os_strlen(tok_prev);
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev,
+ domain_len);
+ domain_ptr += domain_len + 1;
+ }
+ }
+
+ os_free(bss->domain_name);
+ bss->domain_name = domain_list;
+ bss->domain_name_len = domain_list_len;
+ } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
+ if (parse_3gpp_cell_net(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "nai_realm") == 0) {
+ if (parse_nai_realm(bss, pos, line) < 0)
+ errors++;
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
bss->gas_frag_limit = atoi(pos);
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
@@ -2439,6 +2835,81 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->dump_msk_file);
bss->dump_msk_file = os_strdup(pos);
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_HS20
+ } else if (os_strcmp(buf, "hs20") == 0) {
+ bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "disable_dgaf") == 0) {
+ bss->disable_dgaf = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
+ if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
+ if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
+ errors++;
+ return errors;
+ }
+ } else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
+ if (hs20_parse_conn_capab(bss, pos, line) < 0) {
+ errors++;
+ return errors;
+ }
+ } else if (os_strcmp(buf, "hs20_operating_class") == 0) {
+ u8 *oper_class;
+ size_t oper_class_len;
+ oper_class_len = os_strlen(pos);
+ if (oper_class_len < 2 || (oper_class_len & 0x01)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_operating_class '%s'",
+ line, pos);
+ errors++;
+ return errors;
+ }
+ oper_class_len /= 2;
+ oper_class = os_malloc(oper_class_len);
+ if (oper_class == NULL) {
+ errors++;
+ return errors;
+ }
+ if (hexstr2bin(pos, oper_class, oper_class_len)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_operating_class '%s'",
+ line, pos);
+ os_free(oper_class);
+ errors++;
+ return errors;
+ }
+ os_free(bss->hs20_operating_class);
+ bss->hs20_operating_class = oper_class;
+ bss->hs20_operating_class_len = oper_class_len;
+#endif /* CONFIG_HS20 */
+ } else if (os_strcmp(buf, "vendor_elements") == 0) {
+ struct wpabuf *elems;
+ size_t len = os_strlen(pos);
+ if (len & 0x01) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "vendor_elements '%s'", line, pos);
+ return 1;
+ }
+ len /= 2;
+ if (len == 0) {
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_alloc(len);
+ if (elems == NULL)
+ return 1;
+
+ if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+ wpabuf_free(elems);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "vendor_elements '%s'", line, pos);
+ return 1;
+ }
+
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = elems;
} else {
wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
"item '%s'", line, buf);
@@ -2472,6 +2943,9 @@ static void hostapd_set_security_params(struct hostapd_bss_config *bss)
}
if (pairwise & WPA_CIPHER_TKIP)
bss->wpa_group = WPA_CIPHER_TKIP;
+ else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+ WPA_CIPHER_GCMP)
+ bss->wpa_group = WPA_CIPHER_GCMP;
else
bss->wpa_group = WPA_CIPHER_CCMP;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 7587e032..1b8bede1 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -523,7 +523,8 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
"ssid=%s\n",
MAC2STR(hapd->own_addr),
- hapd->conf->ssid.ssid);
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
@@ -618,6 +619,12 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
} else if (hapd->conf->wpa &&
+ hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ } else if (hapd->conf->wpa &&
hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
if (ret < 0 || ret >= end - pos)
@@ -637,6 +644,12 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+ if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "GCMP ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "TKIP ");
if (ret < 0 || ret >= end - pos)
@@ -662,6 +675,12 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+ if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "GCMP ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "TKIP ");
if (ret < 0 || ret >= end - pos)
@@ -746,6 +765,36 @@ static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
}
+static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
+{
+ if (hostapd_enable_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Enabling of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
+{
+ if (hostapd_reload_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Reloading of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
+{
+ if (hostapd_disable_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Disabling of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -898,6 +947,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "GET ", 4) == 0) {
reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
reply_size);
+ } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
+ if (hostapd_ctrl_iface_enable(hapd->iface))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
+ if (hostapd_ctrl_iface_reload(hapd->iface))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
+ if (hostapd_ctrl_iface_disable(hapd->iface))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -1091,6 +1149,220 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
}
+static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_add_iface(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_remove_iface(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
+static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ void *interfaces = eloop_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char reply[24];
+ int reply_len;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+
+ os_memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (os_strcmp(buf, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (os_strncmp(buf, "ADD ", 4) == 0) {
+ if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
+ if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
+ reply_len = -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
+ "ignored");
+ reply_len = -1;
+ }
+
+ if (reply_len < 0) {
+ os_memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+}
+
+
+static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
+{
+ char *buf;
+ size_t len;
+
+ if (interface->global_iface_path == NULL)
+ return NULL;
+
+ len = os_strlen(interface->global_iface_path) +
+ os_strlen(interface->global_iface_name) + 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+
+ os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
+ interface->global_iface_name);
+ buf[len - 1] = '\0';
+ return buf;
+}
+
+
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+ struct sockaddr_un addr;
+ int s = -1;
+ char *fname = NULL;
+
+ if (interface->global_iface_path == NULL) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
+ return 0;
+ }
+
+ if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ }
+
+ if (os_strlen(interface->global_iface_path) + 1 +
+ os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+ addr.sun_family = AF_UNIX;
+ fname = hostapd_global_ctrl_iface_path(interface);
+ if (fname == NULL)
+ goto fail;
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+ strerror(errno));
+ if (connect(s, (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(fname) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ fname);
+ goto fail;
+ }
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'", fname);
+ } 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", fname);
+ os_free(fname);
+ fname = NULL;
+ goto fail;
+ }
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ os_free(fname);
+
+ interface->global_ctrl_sock = s;
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ interface, NULL);
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+ return -1;
+}
+
+
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
+{
+ char *fname = NULL;
+
+ if (interfaces->global_ctrl_sock > -1) {
+ eloop_unregister_read_sock(interfaces->global_ctrl_sock);
+ close(interfaces->global_ctrl_sock);
+ interfaces->global_ctrl_sock = -1;
+ fname = hostapd_global_ctrl_iface_path(interfaces);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+
+ if (interfaces->global_iface_path &&
+ rmdir(interfaces->global_iface_path) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ perror("rmdir[ctrl_interface]");
+ }
+ }
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+ }
+}
+
+
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
const char *buf, size_t len)
{
diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h
index 64a50803..3341a66b 100644
--- a/hostapd/ctrl_iface.h
+++ b/hostapd/ctrl_iface.h
@@ -12,6 +12,8 @@
#ifndef CONFIG_NO_CTRL_IFACE
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
@@ -21,6 +23,17 @@ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
{
}
+
+static inline int
+hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+ return 0;
+}
+
+static inline void
+hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
+{
+}
#endif /* CONFIG_NO_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 9c5b13a4..204aa768 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -167,6 +167,10 @@ CONFIG_IPV6=y
# automatically create bridge and VLAN interfaces if necessary.
#CONFIG_FULL_DYNAMIC_VLAN=y
+# Use netlink-based kernel API for VLAN operations instead of ioctl()
+# Note: This requires libnl 3.1 or newer.
+#CONFIG_VLAN_NETLINK=y
+
# Remove support for dumping state into a file on SIGUSR1 signal
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
@@ -257,3 +261,9 @@ CONFIG_IPV6=y
# This can be used to enable functionality to improve interworking with
# external networks.
#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Enable SQLite database support in hlr_auc_gw
+#CONFIG_SQLITE=y
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
index 089c7b23..0a7ff918 100644
--- a/hostapd/eap_register.c
+++ b/hostapd/eap_register.c
@@ -39,6 +39,11 @@ int eap_server_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_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 516d859d..e27ddaba 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -43,6 +43,9 @@
#include "includes.h"
#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "crypto/milenage.h"
@@ -89,6 +92,140 @@ static struct milenage_parameters *milenage_db = NULL;
#define EAP_AKA_CK_LEN 16
+#ifdef CONFIG_SQLITE
+
+static sqlite3 *sqlite_db = NULL;
+static struct milenage_parameters db_tmp_milenage;
+
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_milenage(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE milenage("
+ " imsi INTEGER PRIMARY KEY NOT NULL,"
+ " ki CHAR(32) NOT NULL,"
+ " opc CHAR(32) NOT NULL,"
+ " amf CHAR(4) NOT NULL,"
+ " sqn CHAR(12) NOT NULL"
+ ");";
+
+ printf("Adding database table for milenage information\n");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ printf("SQLite error: %s\n", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+ sqlite3 *db;
+
+ if (sqlite3_open(db_file, &db)) {
+ printf("Failed to open database %s: %s\n",
+ db_file, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "milenage") &&
+ db_table_create_milenage(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+
+static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct milenage_parameters *m = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
+ printf("Invalid ki value in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
+ printf("Invalid opcvalue in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
+ printf("Invalid amf value in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
+ printf("Invalid sqn value in database\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
+{
+ char cmd[128];
+ unsigned long long imsi;
+
+ os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
+ imsi = atoll(imsi_txt);
+ os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
+ "%llu", imsi);
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
+ imsi);
+ if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
+ NULL) != SQLITE_OK)
+ return NULL;
+
+ return &db_tmp_milenage;
+}
+
+
+static int db_update_milenage_sqn(struct milenage_parameters *m)
+{
+ char cmd[128], val[13], *pos;
+
+ pos = val;
+ pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
+ *pos = '\0';
+ os_snprintf(cmd, sizeof(cmd),
+ "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
+ val, m->imsi);
+ if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ printf("Failed to update SQN in database for IMSI %s\n",
+ m->imsi);
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
static int open_socket(const char *path)
{
struct sockaddr_un addr;
@@ -460,6 +597,11 @@ static struct milenage_parameters * get_milenage(const char *imsi)
m = m->next;
}
+#ifdef CONFIG_SQLITE
+ if (!m)
+ m = db_get_milenage(imsi);
+#endif /* CONFIG_SQLITE */
+
return m;
}
@@ -577,6 +719,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
size_t res_len;
int ret;
struct milenage_parameters *m;
+ int failed = 0;
m = get_milenage(imsi);
if (m) {
@@ -584,6 +727,9 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
return;
res_len = EAP_AKA_RES_MAX_LEN;
inc_sqn(m->sqn);
+#ifdef CONFIG_SQLITE
+ db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
sqn_changes = 1;
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
m->sqn[0], m->sqn[1], m->sqn[2],
@@ -601,7 +747,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
memset(res, '2', EAP_AKA_RES_MAX_LEN);
res_len = EAP_AKA_RES_MAX_LEN;
#else /* AKA_USE_FIXED_TEST_VALUES */
- return;
+ failed = 1;
#endif /* AKA_USE_FIXED_TEST_VALUES */
}
@@ -611,6 +757,13 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
if (ret < 0 || ret >= end - pos)
return;
pos += ret;
+ if (failed) {
+ ret = snprintf(pos, end - pos, "FAILURE");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ goto done;
+ }
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
@@ -621,6 +774,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
+done:
printf("Send: %s\n", reply);
if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
@@ -668,6 +822,9 @@ static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
printf("AKA-AUTS: Re-synchronized: "
"SQN=%02x%02x%02x%02x%02x%02x\n",
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+#ifdef CONFIG_SQLITE
+ db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
sqn_changes = 1;
}
}
@@ -734,6 +891,13 @@ static void cleanup(void)
close(serv_sock);
unlink(socket_path);
+
+#ifdef CONFIG_SQLITE
+ if (sqlite_db) {
+ sqlite3_close(sqlite_db);
+ sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
}
@@ -753,7 +917,7 @@ static void usage(void)
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>] \\\n"
- " [-i<IND len in bits>]\n"
+ " [-D<DB file>] [-i<IND len in bits>]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
@@ -762,6 +926,7 @@ static void usage(void)
" (default: %s)\n"
" -g<triplet file> = path for GSM authentication triplets\n"
" -m<milenage file> = path for Milenage keys\n"
+ " -D<DB file> = path to SQLite database\n"
" -i<IND len in bits> = IND length for SQN (default: 5)\n",
default_socket_path);
}
@@ -771,6 +936,7 @@ int main(int argc, char *argv[])
{
int c;
char *gsm_triplet_file = NULL;
+ char *sqlite_db_file = NULL;
if (os_program_init())
return -1;
@@ -778,10 +944,18 @@ int main(int argc, char *argv[])
socket_path = default_socket_path;
for (;;) {
- c = getopt(argc, argv, "g:hi:m:s:u");
+ c = getopt(argc, argv, "D:g:hi:m:s:u");
if (c < 0)
break;
switch (c) {
+ case 'D':
+#ifdef CONFIG_SQLITE
+ sqlite_db_file = optarg;
+ break;
+#else /* CONFIG_SQLITE */
+ printf("No SQLite support included in the build\n");
+ return -1;
+#endif /* CONFIG_SQLITE */
case 'g':
gsm_triplet_file = optarg;
break;
@@ -810,6 +984,16 @@ int main(int argc, char *argv[])
}
}
+ if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
+ usage();
+ return -1;
+ }
+
+#ifdef CONFIG_SQLITE
+ if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
+ return -1;
+#endif /* CONFIG_SQLITE */
+
if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
return -1;
@@ -829,6 +1013,13 @@ int main(int argc, char *argv[])
for (;;)
process(serv_sock);
+#ifdef CONFIG_SQLITE
+ if (sqlite_db) {
+ sqlite3_close(sqlite_db);
+ sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
+
os_program_deinit();
return 0;
diff --git a/hostapd/hlr_auc_gw.txt b/hostapd/hlr_auc_gw.txt
new file mode 100644
index 00000000..e4b67831
--- /dev/null
+++ b/hostapd/hlr_auc_gw.txt
@@ -0,0 +1,98 @@
+HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+
+hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
+database/authentication gateway interface to HLR/AuC. It could be
+replaced with an implementation of SS7 gateway to GSM/UMTS
+authentication center (HLR/AuC). hostapd will send SIM/AKA
+authentication queries over a UNIX domain socket to and external
+program, e.g., hlr_auc_gw.
+
+hlr_auc_gw can be configured with GSM and UMTS authentication data with
+text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
+hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
+dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
+GSM triplet data is used for a more static configuration (e.g., triplets
+extracted from a SIM card).
+
+Alternatively, hlr_auc_gw can be built with support for an SQLite
+database for more dynamic operations. This is enabled by adding
+"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
+clean; make hlr_auc_gw" in this directory).
+
+hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
+hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
+is configured with command line parameters:
+
+hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
+ [-D<DB file>] [-i<IND len in bits>]
+
+options:
+ -h = show this usage help
+ -u = update SQN in Milenage file on exit
+ -s<socket path> = path for UNIX domain socket
+ (default: /tmp/hlr_auc_gw.sock)
+ -g<triplet file> = path for GSM authentication triplets
+ -m<milenage file> = path for Milenage keys
+ -D<DB file> = path to SQLite database
+ -i<IND len in bits> = IND length for SQN (default: 5)
+
+
+The SQLite database can be initialized with sqlite, e.g., by running
+following commands in "sqlite3 /path/to/hlr_auc_gw.db":
+
+CREATE TABLE milenage(
+ imsi INTEGER PRIMARY KEY NOT NULL,
+ ki CHAR(32) NOT NULL,
+ opc CHAR(32) NOT NULL,
+ amf CHAR(4) NOT NULL,
+ sqn CHAR(12) NOT NULL
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+ 232010000000000,
+ '90dca4eda45b53cf0f12d7c9c3bc6a89',
+ 'cb9cccc4b9258e6dca4760379fb82581',
+ '61df',
+ '000000000000'
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+ 555444333222111,
+ '5122250214c33e723a5dd523fc145fc0',
+ '981d464c7c52eb6e5036234984ad0bcf',
+ 'c3ab',
+ '16f3b3f70fc1'
+);
+
+
+"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
+Milenage parameters based on IMSI from the database. The database can be
+updated dynamically while hlr_auc_gw is running to add/remove/modify
+entries.
+
+
+Example configuration files for hostapd to operate as a RADIUS
+authentication server for EAP-SIM/AKA/AKA':
+
+hostapd.conf:
+
+driver=none
+radius_server_clients=hostapd.radius_clients
+eap_server=1
+eap_user_file=hostapd.eap_user
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+eap_sim_aka_result_ind=1
+
+hostapd.radius_clients:
+
+0.0.0.0/0 radius
+
+hostapd.eap_user:
+
+"0"* AKA
+"1"* SIM
+"2"* AKA
+"3"* SIM
+"4"* AKA
+"5"* SIM
+"6"* AKA'
+"7"* AKA'
+"8"* AKA'
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index daa03d21..5a2c2ea7 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -84,6 +84,11 @@ ctrl_interface_group=0
# SSID to be used in IEEE 802.11 management frames
ssid=test
+# Alternative formats for configuring SSID
+# (double quoted string, hexdump, printf-escaped string)
+#ssid2="test"
+#ssid2=74657374
+#ssid2=P"hello\nthere"
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
# Set as needed to indicate country in which device is operating.
@@ -196,6 +201,13 @@ auth_algs=3
# requests for broadcast SSID
ignore_broadcast_ssid=0
+# Additional vendor specfic 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)
+#vendor_elements=dd0411223301
+
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
# queues: data0, data1, data2, data3, after_beacon, beacon
@@ -489,7 +501,7 @@ wmm_ac_vo_acm=0
# else reserved (default)
#
# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
-# Beamformer’s capability indicating the maximum value of the NUM_STS parameter
+# Beamformer's capability indicating the maximum value of the NUM_STS parameter
# in the TXVECTOR of a VHT NDP
# If SU beamformer capable, set to maximum value minus 1
# else reserved (default)
@@ -522,7 +534,7 @@ wmm_ac_vo_acm=0
# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
# This field is an integer in the range of 0 to 7.
# The length defined by this field is equal to
-# 2 pow(13 + Maximum A-MPDU Length Exponent) –1 octets
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
#
# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
# Indicates whether or not the STA supports link adaptation using VHT variant
@@ -545,7 +557,21 @@ wmm_ac_vo_acm=0
# 0 = Tx antenna pattern might change during the lifetime of an association
# 1 = Tx antenna pattern does not change during the lifetime of an association
#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
##### IEEE 802.1X-2004 related configuration ##################################
@@ -796,6 +822,12 @@ own_ip_addr=127.0.0.1
# to the bridge.
#vlan_tagged_interface=eth0
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
# Arbitrary RADIUS attributes can be added into Access-Request and
# Accounting-Request packets by specifying the contents of the attributes with
# the following configuration parameters. There can be multiple of these to
@@ -1311,7 +1343,7 @@ own_ip_addr=127.0.0.1
# Arbitrary number of Roaming Consortium OIs can be configured with each line
# adding a new OI to the list. The first three entries are available through
# Beacon and Probe Response frames. Any additional entry will be available only
-# through ANQP queries. Each OI is between 3 and 15 octets and is configured a
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
# a hexstring.
#roaming_consortium=021122
#roaming_consortium=2233445566
@@ -1325,6 +1357,124 @@ own_ip_addr=127.0.0.1
#venue_name=eng:Example venue
#venue_name=fin:Esimerkkipaikka
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+# 0 = Realm formatted in accordance with IETF RFC 4282
+# 1 = UTF-8 formatted character string that is not formatted in
+# accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+# 10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+# (encoded as two hex digits)
+# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+# 1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+# 1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 0c33d5bc..aed981c4 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -71,6 +71,7 @@ static const char *commands_help =
" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
" wps_check_pin <PIN> verify PIN checksum\n"
" wps_pbc indicate button pushed to initiate PBC\n"
+" wps_cancel cancel the pending WPS operation\n"
#ifdef CONFIG_WPS_OOB
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
#endif /* CONFIG_WPS_OOB */
@@ -977,7 +978,7 @@ static void hostapd_cli_interactive(void)
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
diff --git a/hostapd/main.c b/hostapd/main.c
index d8c27765..56f00023 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -166,14 +166,9 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
if (hapd_iface == NULL)
goto fail;
- hapd_iface->reload_config = hostapd_reload_config;
- hapd_iface->config_read_cb = hostapd_config_read;
hapd_iface->config_fname = os_strdup(config_file);
if (hapd_iface->config_fname == NULL)
goto fail;
- hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
- hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
- hapd_iface->for_each_interface = hostapd_for_each_interface;
conf = hostapd_config_read(hapd_iface->config_fname);
if (conf == NULL)
@@ -181,7 +176,7 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
hapd_iface->conf = conf;
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)
goto fail;
@@ -248,13 +243,13 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
}
params.bssid = b;
params.ifname = hapd->conf->iface;
- params.ssid = (const u8 *) hapd->conf->ssid.ssid;
+ params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.test_socket = hapd->conf->test_socket;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
- params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
+ params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
if (params.bridge == NULL)
return -1;
for (i = 0; i < hapd->iface->num_bss; i++) {
@@ -284,21 +279,6 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
}
-static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
-{
- const struct wpa_driver_ops *driver;
- void *drv_priv;
- if (iface == NULL)
- return;
- driver = iface->bss[0]->driver;
- drv_priv = iface->bss[0]->drv_priv;
- hostapd_interface_deinit(iface);
- if (driver && driver->hapd_deinit && drv_priv)
- driver->hapd_deinit(drv_priv);
- hostapd_interface_free(iface);
-}
-
-
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
@@ -411,7 +391,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
wpa_printf(MSG_ERROR, "No drivers enabled");
return -1;
}
- global.drv_priv = os_zalloc(global.drv_count * sizeof(void *));
+ global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
if (global.drv_priv == NULL)
return -1;
@@ -499,13 +479,15 @@ static void usage(void)
fprintf(stderr,
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
- "<configuration file(s)>\n"
+ "\\\n"
+ " [-g <global ctrl_iface>] <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
" -d show more debug messages (-dd for even more)\n"
" -B run daemon in the background\n"
" -e entropy file\n"
+ " -g global control interface path\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
@@ -527,6 +509,28 @@ static const char * hostapd_msg_ifname_cb(void *ctx)
}
+static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
+ const char *path)
+{
+ char *pos;
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = os_strdup(path);
+ if (interfaces->global_iface_path == NULL)
+ return -1;
+ pos = os_strrchr(interfaces->global_iface_path, '/');
+ if (pos == NULL) {
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+ return -1;
+ }
+
+ *pos = '\0';
+ interfaces->global_iface_name = pos + 1;
+
+ return 0;
+}
+
+
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
@@ -540,8 +544,19 @@ int main(int argc, char *argv[])
if (os_program_init())
return -1;
+ os_memset(&interfaces, 0, sizeof(interfaces));
+ interfaces.reload_config = hostapd_reload_config;
+ interfaces.config_read_cb = hostapd_config_read;
+ interfaces.for_each_interface = hostapd_for_each_interface;
+ interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
+ interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+ interfaces.driver_init = hostapd_driver_init;
+ interfaces.global_iface_path = NULL;
+ interfaces.global_iface_name = NULL;
+ interfaces.global_ctrl_sock = -1;
+
for (;;) {
- c = getopt(argc, argv, "Bde:f:hKP:tv");
+ c = getopt(argc, argv, "Bde:f:hKP:tvg:");
if (c < 0)
break;
switch (c) {
@@ -576,6 +591,9 @@ int main(int argc, char *argv[])
show_version();
exit(1);
break;
+ case 'g':
+ hostapd_get_global_ctrl_iface(&interfaces, optarg);
+ break;
default:
usage();
@@ -583,7 +601,7 @@ int main(int argc, char *argv[])
}
}
- if (optind == argc)
+ if (optind == argc && interfaces.global_iface_path == NULL)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
@@ -592,11 +610,13 @@ int main(int argc, char *argv[])
wpa_debug_open_file(log_file);
interfaces.count = argc - optind;
- interfaces.iface = os_zalloc(interfaces.count *
- sizeof(struct hostapd_iface *));
- if (interfaces.iface == NULL) {
- wpa_printf(MSG_ERROR, "malloc failed");
- return -1;
+ if (interfaces.count) {
+ interfaces.iface = os_calloc(interfaces.count,
+ sizeof(struct hostapd_iface *));
+ if (interfaces.iface == NULL) {
+ wpa_printf(MSG_ERROR, "malloc failed");
+ return -1;
+ }
}
if (hostapd_global_init(&interfaces, entropy_file))
@@ -611,12 +631,15 @@ int main(int argc, char *argv[])
goto out;
}
+ hostapd_global_ctrl_iface_init(&interfaces);
+
if (hostapd_global_run(&interfaces, daemonize, pid_file))
goto out;
ret = 0;
out:
+ hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++)
hostapd_interface_deinit_free(interfaces.iface[i]);
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 2c3a6d9f..7563b52e 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -28,6 +28,8 @@
static void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta);
+static void accounting_sta_interim(struct hostapd_data *hapd,
+ struct sta_info *sta);
static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
@@ -40,7 +42,6 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
size_t len;
int i;
struct wpabuf *b;
- struct hostapd_radius_attr *attr;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@@ -80,7 +81,17 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
}
if (sta) {
+ /* Use 802.1X identity if available */
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
+
+ /* Use RADIUS ACL identity if 802.1X provides no identity */
+ if (!val && sta->identity) {
+ val = (u8 *) sta->identity;
+ len = os_strlen(sta->identity);
+ }
+
+ /* Use STA MAC if neither 802.1X nor RADIUS ACL provided
+ * identity */
if (!val) {
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
MAC2STR(sta->addr));
@@ -95,86 +106,11 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
}
}
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_IP_ADDRESS) &&
- hapd->conf->own_ip_addr.af == AF_INET &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
- printf("Could not add NAS-IP-Address\n");
- goto fail;
- }
-
-#ifdef CONFIG_IPV6
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
- hapd->conf->own_ip_addr.af == AF_INET6 &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
- printf("Could not add NAS-IPv6-Address\n");
+ if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
+ msg) < 0)
goto fail;
- }
-#endif /* CONFIG_IPV6 */
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_IDENTIFIER) &&
- hapd->conf->nas_identifier &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
- (u8 *) hapd->conf->nas_identifier,
- os_strlen(hapd->conf->nas_identifier))) {
- printf("Could not add NAS-Identifier\n");
- goto fail;
- }
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_PORT) &&
- sta &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
- printf("Could not add NAS-Port\n");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_CALLED_STATION_ID) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Called-Station-Id\n");
- goto fail;
- }
if (sta) {
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
- MAC2STR(sta->addr));
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Calling-Station-Id\n");
- goto fail;
- }
-
- if (!hostapd_config_get_radius_attr(
- hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_PORT_TYPE) &&
- !radius_msg_add_attr_int32(
- msg, RADIUS_ATTR_NAS_PORT_TYPE,
- RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
- printf("Could not add NAS-Port-Type\n");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
- radius_sta_rate(hapd, sta) / 2,
- (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
- radius_mode_txt(hapd));
- if (!hostapd_config_get_radius_attr(
- hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_CONNECT_INFO) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Connect-Info\n");
- goto fail;
- }
-
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
i);
@@ -196,15 +132,13 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
wpa_printf(MSG_ERROR, "Could not add CUI");
goto fail;
}
- }
- for (attr = hapd->conf->radius_acct_req_attr; attr; attr = attr->next)
- {
- if (!radius_msg_add_attr(msg, attr->type,
- wpabuf_head(attr->val),
- wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
+ if (!b && sta->radius_cui &&
+ !radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ (u8 *) sta->radius_cui,
+ os_strlen(sta->radius_cui))) {
+ wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
goto fail;
}
}
@@ -415,7 +349,8 @@ static void accounting_sta_report(struct hostapd_data *hapd,
* @hapd: hostapd BSS data
* @sta: The station
*/
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
+static void accounting_sta_interim(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
if (sta->acct_session_started)
accounting_sta_report(hapd, sta, 0);
diff --git a/src/ap/accounting.h b/src/ap/accounting.h
index 797e24d7..9d13d011 100644
--- a/src/ap/accounting.h
+++ b/src/ap/accounting.h
@@ -9,7 +9,6 @@
#ifndef ACCOUNTING_H
#define ACCOUNTING_H
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_NO_ACCOUNTING
static inline void accounting_sta_start(struct hostapd_data *hapd,
struct sta_info *sta)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 2af2a8e5..fd2d4d56 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -104,9 +104,9 @@ struct hostapd_config * hostapd_config_defaults(void)
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, 1 };
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
- { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
const struct hostapd_tx_queue_params txq_bk =
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
const struct hostapd_tx_queue_params txq_be =
@@ -506,10 +506,23 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->roaming_consortium);
os_free(conf->venue_name);
+ os_free(conf->nai_realm_data);
+ os_free(conf->network_auth_type);
+ os_free(conf->anqp_3gpp_cell_net);
+ os_free(conf->domain_name);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
+
+#ifdef CONFIG_HS20
+ os_free(conf->hs20_oper_friendly_name);
+ os_free(conf->hs20_wan_metrics);
+ os_free(conf->hs20_connection_capability);
+ os_free(conf->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+ wpabuf_free(conf->vendor_elements);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ca4fe58c..f5e4a6a5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -12,6 +12,7 @@
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#define MAX_STA_COUNT 2007
@@ -48,7 +49,7 @@ typedef enum hostap_security_policy {
} secpolicy;
struct hostapd_ssid {
- char ssid[HOSTAPD_MAX_SSID_LEN + 1];
+ u8 ssid[HOSTAPD_MAX_SSID_LEN];
size_t ssid_len;
int ssid_set;
@@ -65,6 +66,10 @@ struct hostapd_ssid {
#define DYNAMIC_VLAN_OPTIONAL 1
#define DYNAMIC_VLAN_REQUIRED 2
int dynamic_vlan;
+#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0
+#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
+#define DYNAMIC_VLAN_NAMING_END 2
+ int vlan_naming;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -132,14 +137,6 @@ struct hostapd_tx_queue_params {
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
};
-struct hostapd_wmm_ac_params {
- int cwmin;
- int cwmax;
- int aifs;
- int txop_limit; /* in units of 32us */
- int admission_control_mandatory;
-};
-
#define MAX_ROAMING_CONSORTIUM_LEN 15
@@ -148,12 +145,29 @@ struct hostapd_roaming_consortium {
u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
};
-struct hostapd_venue_name {
+struct hostapd_lang_string {
u8 lang[3];
u8 name_len;
u8 name[252];
};
+#define MAX_NAI_REALMS 10
+#define MAX_NAI_REALMLEN 255
+#define MAX_NAI_EAP_METHODS 5
+#define MAX_NAI_AUTH_TYPES 4
+struct hostapd_nai_realm_data {
+ u8 encoding;
+ char realm_buf[MAX_NAI_REALMLEN + 1];
+ char *realm[MAX_NAI_REALMS];
+ u8 eap_method_count;
+ struct hostapd_nai_realm_eap {
+ u8 eap_method;
+ u8 num_auths;
+ u8 auth_id[MAX_NAI_AUTH_TYPES];
+ u8 auth_val[MAX_NAI_AUTH_TYPES];
+ } eap_method[MAX_NAI_EAP_METHODS];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -389,16 +403,49 @@ struct hostapd_bss_config {
/* IEEE 802.11u - Venue Name duples */
unsigned int venue_name_count;
- struct hostapd_venue_name *venue_name;
+ struct hostapd_lang_string *venue_name;
+
+ /* IEEE 802.11u - Network Authentication Type */
+ u8 *network_auth_type;
+ size_t network_auth_type_len;
+
+ /* IEEE 802.11u - IP Address Type Availability */
+ u8 ipaddr_type_availability;
+ u8 ipaddr_type_configured;
+
+ /* IEEE 802.11u - 3GPP Cellular Network */
+ u8 *anqp_3gpp_cell_net;
+ size_t anqp_3gpp_cell_net_len;
+
+ /* IEEE 802.11u - Domain Name */
+ u8 *domain_name;
+ size_t domain_name_len;
+
+ unsigned int nai_realm_count;
+ struct hostapd_nai_realm_data *nai_realm_data;
u16 gas_comeback_delay;
int gas_frag_limit;
+#ifdef CONFIG_HS20
+ int hs20;
+ int disable_dgaf;
+ unsigned int hs20_oper_friendly_name_count;
+ struct hostapd_lang_string *hs20_oper_friendly_name;
+ u8 *hs20_wan_metrics;
+ u8 *hs20_connection_capability;
+ size_t hs20_connection_capability_len;
+ u8 *hs20_operating_class;
+ u8 hs20_operating_class_len;
+#endif /* CONFIG_HS20 */
+
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+
+ struct wpabuf *vendor_elements;
};
@@ -455,7 +502,9 @@ struct hostapd_config {
int require_ht;
u32 vht_capab;
int ieee80211ac;
+ int require_vht;
u8 vht_oper_chwidth;
+ u8 vht_oper_centr_freq_seg0_idx;
};
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 859b529b..02da25b7 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -12,11 +12,13 @@
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#include "p2p/p2p.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
+#include "hs20.h"
#include "ap_drv_ops.h"
@@ -147,6 +149,30 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_WIFI_DISPLAY
+ if (hapd->p2p_group) {
+ struct wpabuf *a;
+ a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
+ if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+ wpabuf_put_buf(assocresp, a);
+ wpabuf_free(a);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_HS20
+ pos = buf;
+ pos = hostapd_eid_hs20_indication(hapd, pos);
+ if (pos != buf) {
+ if (wpabuf_resize(&beacon, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(beacon, buf, pos - buf);
+
+ if (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+ }
+#endif /* CONFIG_HS20 */
+
*beacon_ret = beacon;
*proberesp_ret = proberesp;
*assocresp_ret = assocresp;
@@ -586,6 +612,16 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
}
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
+ const u8 *peer, u8 *buf, u16 *buf_len)
+{
+ if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
+ return 0;
+ return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
+ buf_len);
+}
+
+
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 169c91b7..9c53b99d 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -101,6 +101,10 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
#include "drivers/driver.h"
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
+ enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 933b1585..18090ca1 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -251,23 +251,9 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
ap->ssid_len = len;
}
- os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
- len = 0;
- if (elems->supp_rates) {
- len = elems->supp_rates_len;
- if (len > WLAN_SUPP_RATES_MAX)
- len = WLAN_SUPP_RATES_MAX;
- os_memcpy(ap->supported_rates, elems->supp_rates, len);
- }
- if (elems->ext_supp_rates) {
- int len2;
- if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
- len2 = WLAN_SUPP_RATES_MAX - len;
- else
- len2 = elems->ext_supp_rates_len;
- os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
- len2);
- }
+ merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
ap->wpa = elems->wpa_ie != NULL;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0f29ccdb..2f813f37 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -33,6 +33,7 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "beacon.h"
+#include "hs20.h"
#ifdef NEED_AP_MLME
@@ -205,6 +206,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
if (hapd->p2p_probe_resp_ie)
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
#endif /* CONFIG_P2P */
+ if (hapd->conf->vendor_elements)
+ buflen += wpabuf_len(hapd->conf->vendor_elements);
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -292,6 +295,16 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_p2p_manage(hapd, pos);
#endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_HS20
+ pos = hostapd_eid_hs20_indication(hapd, pos);
+#endif /* CONFIG_HS20 */
+
+ if (hapd->conf->vendor_elements) {
+ os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
+ wpabuf_len(hapd->conf->vendor_elements));
+ pos += wpabuf_len(hapd->conf->vendor_elements);
+ }
+
*resp_len = pos - (u8 *) resp;
return (u8 *) resp;
}
@@ -523,6 +536,8 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
if (hapd->p2p_beacon_ie)
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
#endif /* CONFIG_P2P */
+ if (hapd->conf->vendor_elements)
+ tail_len += wpabuf_len(hapd->conf->vendor_elements);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -629,6 +644,16 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
#endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_HS20
+ tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+#endif /* CONFIG_HS20 */
+
+ if (hapd->conf->vendor_elements) {
+ os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
+ wpabuf_len(hapd->conf->vendor_elements));
+ tailpos += wpabuf_len(hapd->conf->vendor_elements);
+ }
+
tail_len = tailpos > tail ? tailpos - tail : 0;
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
@@ -644,7 +669,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
params.dtim_period = hapd->conf->dtim_period;
params.beacon_int = hapd->iconf->beacon_int;
params.basic_rates = hapd->iconf->basic_rates;
- params.ssid = (u8 *) hapd->conf->ssid.ssid;
+ params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
@@ -694,6 +719,9 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
params.hessid = hapd->conf->hessid;
params.access_network_type = hapd->conf->access_network_type;
params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_HS20
+ params.disable_dgaf = hapd->conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
if (hostapd_drv_set_ap(hapd, &params))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index cf06a4fb..23fa241a 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -16,6 +16,7 @@
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
+#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
@@ -37,7 +38,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
+#ifdef CONFIG_IEEE80211R
+ u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+ u8 *p = buf;
+#endif /* CONFIG_IEEE80211R */
u16 reason = WLAN_REASON_UNSPECIFIED;
+ u16 status = WLAN_STATUS_SUCCESS;
if (addr == NULL) {
/*
@@ -146,27 +152,85 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
- ie, ielen, NULL, 0);
+ ie, ielen,
+ elems.mdie, elems.mdie_len);
if (res != WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
"rejected? (res %u)", res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
- if (res == WPA_INVALID_GROUP)
+ if (res == WPA_INVALID_GROUP) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_PAIRWISE)
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ } else if (res == WPA_INVALID_PAIRWISE) {
reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_AKMP)
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ } else if (res == WPA_INVALID_AKMP) {
reason = WLAN_REASON_AKMP_NOT_VALID;
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ }
#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
reason = WLAN_REASON_INVALID_IE;
- else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ status = WLAN_STATUS_INVALID_IE;
+ } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ }
#endif /* CONFIG_IEEE80211W */
- else
+ else {
reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ }
goto fail;
}
+#ifdef CONFIG_IEEE80211W
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ (sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA
+ * Query timeout has not been reached. Reject the
+ * association attempt temporarily and start SA Query,
+ * if one is not pending.
+ */
+
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+#ifdef CONFIG_IEEE80211R
+ status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+ p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+ p - buf);
+#endif /* CONFIG_IEEE80211R */
+ return 0;
+ }
+
+ if (wpa_auth_uses_mfp(sta->wpa_sm))
+ sta->flags |= WLAN_STA_MFP;
+ else
+ sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+ if (sta->auth_alg == WLAN_AUTH_FT) {
+ status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
+ req_ies_len);
+ if (status != WLAN_STATUS_SUCCESS) {
+ if (status == WLAN_STATUS_INVALID_PMKID)
+ reason = WLAN_REASON_INVALID_IE;
+ if (status == WLAN_STATUS_INVALID_MDIE)
+ reason = WLAN_REASON_INVALID_IE;
+ if (status == WLAN_STATUS_INVALID_FTIE)
+ reason = WLAN_REASON_INVALID_IE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -178,6 +242,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#ifdef CONFIG_WPS_STRICT
if (wps && wps_validate_assoc_req(wps) < 0) {
reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
wpabuf_free(wps);
goto fail;
}
@@ -198,9 +263,24 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
skip_wpa_check:
#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+ p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
+ sta->auth_alg, req_ies, req_ies_len);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#else /* CONFIG_IEEE80211R */
+ /* Keep compiler silent about unused variables */
+ if (status) {
+ }
+#endif /* CONFIG_IEEE80211R */
+
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
- wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+
+ if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+ else
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
@@ -216,6 +296,9 @@ skip_wpa_check:
return 0;
fail:
+#ifdef CONFIG_IEEE80211R
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#endif /* CONFIG_IEEE80211R */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
return -1;
@@ -326,6 +409,110 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
#ifdef HOSTAPD
+#ifdef CONFIG_IEEE80211R
+static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
+ const u8 *bssid,
+ u16 auth_transaction, u16 status,
+ const u8 *ies, size_t ies_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, dst);
+ if (sta == NULL)
+ return;
+
+ hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+ sta->flags |= WLAN_STA_AUTH;
+
+ hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void hostapd_notif_auth(struct hostapd_data *hapd,
+ struct auth_info *rx_auth)
+{
+ struct sta_info *sta;
+ u16 status = WLAN_STATUS_SUCCESS;
+ u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+ size_t resp_ies_len = 0;
+
+ sta = ap_get_sta(hapd, rx_auth->peer);
+ if (!sta) {
+ sta = ap_sta_add(hapd, rx_auth->peer);
+ if (sta == NULL) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+ sta->flags &= ~WLAN_STA_PREAUTH;
+ ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+#ifdef CONFIG_IEEE80211R
+ if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
+ sta->auth_alg = WLAN_AUTH_FT;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+ "state machine");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
+ rx_auth->auth_transaction, rx_auth->ies,
+ rx_auth->ies_len,
+ hostapd_notify_auth_ft_finish, hapd);
+ return;
+ }
+#endif /* CONFIG_IEEE80211R */
+fail:
+ hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
+ status, resp_ies, resp_ies_len);
+}
+
+
+static void hostapd_action_rx(struct hostapd_data *hapd,
+ struct rx_action *action)
+{
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
+ action->category, (int) action->len);
+
+ sta = ap_get_sta(hapd, action->sa);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+ return;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (action->category == WLAN_ACTION_FT) {
+ wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
+ __func__, (int) action->len);
+ wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
+ wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
+ __func__, (int) action->len);
+ ieee802_11_sa_query_action(hapd, action->sa,
+ *(action->data + 1),
+ action->data + 2);
+ }
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211V
+ if (action->category == WLAN_ACTION_WNM) {
+ wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
+ __func__, (int) action->len);
+ ieee802_11_rx_wnm_action_ap(hapd, action);
+ }
+#endif /* CONFIG_IEEE80211V */
+}
+
+
#ifdef NEED_AP_MLME
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
@@ -505,7 +692,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_DEBUG;
- if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+ if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
@@ -610,14 +797,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
-#ifdef NEED_AP_MLME
case EVENT_RX_ACTION:
if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
data->rx_action.bssid == NULL)
break;
+#ifdef NEED_AP_MLME
hostapd_rx_action(hapd, &data->rx_action);
- break;
#endif /* NEED_AP_MLME */
+ hostapd_action_rx(hapd, &data->rx_action);
+ break;
+ case EVENT_AUTH:
+ hostapd_notif_auth(hapd, &data->auth);
+ break;
case EVENT_CH_SWITCH:
if (!data)
break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 2177b02a..53e6cbbe 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -128,6 +128,31 @@ static void gas_serv_free_dialogs(struct hostapd_data *hapd,
}
+static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ u8 *len;
+
+ len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+ if (hapd->conf->hs20_oper_friendly_name)
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ if (hapd->conf->hs20_wan_metrics)
+ wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+ if (hapd->conf->hs20_connection_capability)
+ wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+ if (hapd->conf->nai_realm_data)
+ wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+ if (hapd->conf->hs20_operating_class)
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+ gas_anqp_set_element_len(buf, len);
+}
+
+
static void anqp_add_capab_list(struct hostapd_data *hapd,
struct wpabuf *buf)
{
@@ -137,8 +162,19 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
if (hapd->conf->venue_name)
wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+ if (hapd->conf->network_auth_type)
+ wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
if (hapd->conf->roaming_consortium)
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+ if (hapd->conf->ipaddr_type_configured)
+ wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+ if (hapd->conf->nai_realm_data)
+ wpabuf_put_le16(buf, ANQP_NAI_REALM);
+ if (hapd->conf->anqp_3gpp_cell_net)
+ wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+ if (hapd->conf->domain_name)
+ wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+ anqp_add_hs_capab_list(hapd, buf);
gas_anqp_set_element_len(buf, len);
}
@@ -152,7 +188,7 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
wpabuf_put_u8(buf, hapd->conf->venue_group);
wpabuf_put_u8(buf, hapd->conf->venue_type);
for (i = 0; i < hapd->conf->venue_name_count; i++) {
- struct hostapd_venue_name *vn;
+ struct hostapd_lang_string *vn;
vn = &hapd->conf->venue_name[i];
wpabuf_put_u8(buf, 3 + vn->name_len);
wpabuf_put_data(buf, vn->lang, 3);
@@ -163,6 +199,18 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
}
+static void anqp_add_network_auth_type(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->network_auth_type) {
+ wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
+ wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
+ wpabuf_put_data(buf, hapd->conf->network_auth_type,
+ hapd->conf->network_auth_type_len);
+ }
+}
+
+
static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
struct wpabuf *buf)
{
@@ -180,10 +228,283 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
}
+static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->ipaddr_type_configured) {
+ wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
+ }
+}
+
+
+static void anqp_add_nai_realm_eap(struct wpabuf *buf,
+ struct hostapd_nai_realm_data *realm)
+{
+ unsigned int i, j;
+
+ wpabuf_put_u8(buf, realm->eap_method_count);
+
+ for (i = 0; i < realm->eap_method_count; i++) {
+ struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
+ wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
+ wpabuf_put_u8(buf, eap->eap_method);
+ wpabuf_put_u8(buf, eap->num_auths);
+ for (j = 0; j < eap->num_auths; j++) {
+ wpabuf_put_u8(buf, eap->auth_id[j]);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, eap->auth_val[j]);
+ }
+ }
+}
+
+
+static void anqp_add_nai_realm_data(struct wpabuf *buf,
+ struct hostapd_nai_realm_data *realm,
+ unsigned int realm_idx)
+{
+ u8 *realm_data_len;
+
+ wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
+ (int) os_strlen(realm->realm[realm_idx]));
+ realm_data_len = wpabuf_put(buf, 2);
+ wpabuf_put_u8(buf, realm->encoding);
+ wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
+ wpabuf_put_str(buf, realm->realm[realm_idx]);
+ anqp_add_nai_realm_eap(buf, realm);
+ gas_anqp_set_element_len(buf, realm_data_len);
+}
+
+
+static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
+ struct wpabuf *buf,
+ const u8 *home_realm,
+ size_t home_realm_len)
+{
+ unsigned int i, j, k;
+ u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
+ struct hostapd_nai_realm_data *realm;
+ const u8 *pos, *realm_name, *end;
+ struct {
+ unsigned int realm_data_idx;
+ unsigned int realm_idx;
+ } matches[10];
+
+ pos = home_realm;
+ end = pos + home_realm_len;
+ if (pos + 1 > end) {
+ wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
+ home_realm, home_realm_len);
+ return -1;
+ }
+ num_realms = *pos++;
+
+ for (i = 0; i < num_realms && num_matching < 10; i++) {
+ if (pos + 2 > end) {
+ wpa_hexdump(MSG_DEBUG,
+ "Truncated NAI Home Realm Query",
+ home_realm, home_realm_len);
+ return -1;
+ }
+ encoding = *pos++;
+ realm_len = *pos++;
+ if (pos + realm_len > end) {
+ wpa_hexdump(MSG_DEBUG,
+ "Truncated NAI Home Realm Query",
+ home_realm, home_realm_len);
+ return -1;
+ }
+ realm_name = pos;
+ for (j = 0; j < hapd->conf->nai_realm_count &&
+ num_matching < 10; j++) {
+ const u8 *rpos, *rend;
+ realm = &hapd->conf->nai_realm_data[j];
+ if (encoding != realm->encoding)
+ continue;
+
+ rpos = realm_name;
+ while (rpos < realm_name + realm_len &&
+ num_matching < 10) {
+ for (rend = rpos;
+ rend < realm_name + realm_len; rend++) {
+ if (*rend == ';')
+ break;
+ }
+ for (k = 0; k < MAX_NAI_REALMS &&
+ realm->realm[k] &&
+ num_matching < 10; k++) {
+ if ((int) os_strlen(realm->realm[k]) !=
+ rend - rpos ||
+ os_strncmp((char *) rpos,
+ realm->realm[k],
+ rend - rpos) != 0)
+ continue;
+ matches[num_matching].realm_data_idx =
+ j;
+ matches[num_matching].realm_idx = k;
+ num_matching++;
+ }
+ rpos = rend + 1;
+ }
+ }
+ pos += realm_len;
+ }
+
+ realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+ wpabuf_put_le16(buf, num_matching);
+
+ /*
+ * There are two ways to format. 1. each realm in a NAI Realm Data unit
+ * 2. all realms that share the same EAP methods in a NAI Realm Data
+ * unit. The first format is likely to be bigger in size than the
+ * second, but may be easier to parse and process by the receiver.
+ */
+ for (i = 0; i < num_matching; i++) {
+ wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
+ matches[i].realm_data_idx, matches[i].realm_idx);
+ realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
+ anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
+ }
+ gas_anqp_set_element_len(buf, realm_list_len);
+ return 0;
+}
+
+
+static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
+ const u8 *home_realm, size_t home_realm_len,
+ int nai_realm, int nai_home_realm)
+{
+ if (nai_realm && hapd->conf->nai_realm_data) {
+ u8 *len;
+ unsigned int i, j;
+ len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+ wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
+ for (i = 0; i < hapd->conf->nai_realm_count; i++) {
+ u8 *realm_data_len, *realm_len;
+ struct hostapd_nai_realm_data *realm;
+
+ realm = &hapd->conf->nai_realm_data[i];
+ realm_data_len = wpabuf_put(buf, 2);
+ wpabuf_put_u8(buf, realm->encoding);
+ realm_len = wpabuf_put(buf, 1);
+ for (j = 0; realm->realm[j]; j++) {
+ if (j > 0)
+ wpabuf_put_u8(buf, ';');
+ wpabuf_put_str(buf, realm->realm[j]);
+ }
+ *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
+ anqp_add_nai_realm_eap(buf, realm);
+ gas_anqp_set_element_len(buf, realm_data_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ } else if (nai_home_realm && hapd->conf->nai_realm_data) {
+ hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
+ home_realm_len);
+ }
+}
+
+
+static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->anqp_3gpp_cell_net) {
+ wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+ wpabuf_put_le16(buf,
+ hapd->conf->anqp_3gpp_cell_net_len);
+ wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
+ hapd->conf->anqp_3gpp_cell_net_len);
+ }
+}
+
+
+static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+ if (hapd->conf->domain_name) {
+ wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+ wpabuf_put_le16(buf, hapd->conf->domain_name_len);
+ wpabuf_put_data(buf, hapd->conf->domain_name,
+ hapd->conf->domain_name_len);
+ }
+}
+
+
+static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_oper_friendly_name) {
+ u8 *len;
+ unsigned int i;
+ len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
+ {
+ struct hostapd_lang_string *vn;
+ vn = &hapd->conf->hs20_oper_friendly_name[i];
+ wpabuf_put_u8(buf, 3 + vn->name_len);
+ wpabuf_put_data(buf, vn->lang, 3);
+ wpabuf_put_data(buf, vn->name, vn->name_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_wan_metrics(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_wan_metrics) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_connection_capability(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_connection_capability) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
+ hapd->conf->hs20_connection_capability_len);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_operating_class(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_operating_class) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
+ hapd->conf->hs20_operating_class_len);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
- struct gas_dialog_info *di)
+ struct gas_dialog_info *di,
+ const u8 *home_realm, size_t home_realm_len)
{
struct wpabuf *buf;
@@ -195,8 +516,31 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_capab_list(hapd, buf);
if (request & ANQP_REQ_VENUE_NAME)
anqp_add_venue_name(hapd, buf);
+ if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
+ anqp_add_network_auth_type(hapd, buf);
if (request & ANQP_REQ_ROAMING_CONSORTIUM)
anqp_add_roaming_consortium(hapd, buf);
+ if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
+ anqp_add_ip_addr_type_availability(hapd, buf);
+ if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
+ anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
+ request & ANQP_REQ_NAI_REALM,
+ request & ANQP_REQ_NAI_HOME_REALM);
+ if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
+ anqp_add_3gpp_cellular_network(hapd, buf);
+ if (request & ANQP_REQ_DOMAIN_NAME)
+ anqp_add_domain_name(hapd, buf);
+
+ if (request & ANQP_REQ_HS_CAPABILITY_LIST)
+ anqp_add_hs_capab_list(hapd, buf);
+ if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
+ anqp_add_operator_friendly_name(hapd, buf);
+ if (request & ANQP_REQ_WAN_METRICS)
+ anqp_add_wan_metrics(hapd, buf);
+ if (request & ANQP_REQ_CONNECTION_CAPABILITY)
+ anqp_add_connection_capability(hapd, buf);
+ if (request & ANQP_REQ_OPERATING_CLASS)
+ anqp_add_operating_class(hapd, buf);
return buf;
}
@@ -216,8 +560,8 @@ static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
struct anqp_query_info {
unsigned int request;
unsigned int remote_request;
- const void *param;
- u32 param_arg;
+ const u8 *home_realm_query;
+ size_t home_realm_query_len;
u16 remote_delay;
};
@@ -252,10 +596,37 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
hapd->conf->venue_name != NULL, 0, 0, qi);
break;
+ case ANQP_NETWORK_AUTH_TYPE:
+ set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
+ hapd->conf->network_auth_type != NULL,
+ 0, 0, qi);
+ break;
case ANQP_ROAMING_CONSORTIUM:
set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
hapd->conf->roaming_consortium != NULL, 0, 0, qi);
break;
+ case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+ set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
+ "IP Addr Type Availability",
+ hapd->conf->ipaddr_type_configured,
+ 0, 0, qi);
+ break;
+ case ANQP_NAI_REALM:
+ set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
+ hapd->conf->nai_realm_data != NULL,
+ 0, 0, qi);
+ break;
+ case ANQP_3GPP_CELLULAR_NETWORK:
+ set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
+ "3GPP Cellular Network",
+ hapd->conf->anqp_3gpp_cell_net != NULL,
+ 0, 0, qi);
+ break;
+ case ANQP_DOMAIN_NAME:
+ set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
+ hapd->conf->domain_name != NULL,
+ 0, 0, qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
info_id);
@@ -278,13 +649,122 @@ static void rx_anqp_query_list(struct hostapd_data *hapd,
}
+static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
+ struct anqp_query_info *qi)
+{
+ switch (subtype) {
+ case HS20_STYPE_CAPABILITY_LIST:
+ set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
+ 1, 0, 0, qi);
+ break;
+ case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+ set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
+ "Operator Friendly Name",
+ hapd->conf->hs20_oper_friendly_name != NULL,
+ 0, 0, qi);
+ break;
+ case HS20_STYPE_WAN_METRICS:
+ set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
+ hapd->conf->hs20_wan_metrics != NULL,
+ 0, 0, qi);
+ break;
+ case HS20_STYPE_CONNECTION_CAPABILITY:
+ set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
+ "Connection Capability",
+ hapd->conf->hs20_connection_capability != NULL,
+ 0, 0, qi);
+ break;
+ case HS20_STYPE_OPERATING_CLASS:
+ set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
+ hapd->conf->hs20_operating_class != NULL,
+ 0, 0, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
+ subtype);
+ break;
+ }
+}
+
+
+static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ qi->request |= ANQP_REQ_NAI_HOME_REALM;
+ qi->home_realm_query = pos;
+ qi->home_realm_query_len = end - pos;
+ if (hapd->conf->nai_realm_data != NULL) {
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
+ "(local)");
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
+ "available");
+ }
+}
+
+
+static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ u32 oui;
+ u8 subtype;
+
+ if (pos + 4 > end) {
+ wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
+ "Query element");
+ return;
+ }
+
+ oui = WPA_GET_BE24(pos);
+ pos += 3;
+ if (oui != OUI_WFA) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
+ oui);
+ return;
+ }
+
+ if (*pos != HS20_ANQP_OUI_TYPE) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
+ *pos);
+ return;
+ }
+ pos++;
+
+ if (pos + 1 >= end)
+ return;
+
+ subtype = *pos++;
+ pos++; /* Reserved */
+ switch (subtype) {
+ case HS20_STYPE_QUERY_LIST:
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
+ while (pos < end) {
+ rx_anqp_hs_query_list(hapd, *pos, qi);
+ pos++;
+ }
+ break;
+ case HS20_STYPE_NAI_HOME_REALM_QUERY:
+ rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
+ "%u", subtype);
+ break;
+ }
+}
+
+
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
struct anqp_query_info *qi)
{
struct wpabuf *buf, *tx_buf;
- buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL);
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+ qi->home_realm_query,
+ qi->home_realm_query_len);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
if (!buf)
@@ -419,6 +899,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
case ANQP_QUERY_LIST:
rx_anqp_query_list(hapd, pos, pos + elen, &qi);
break;
+ case ANQP_VENDOR_SPECIFIC:
+ rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
"Request element %u", info_id);
@@ -442,7 +925,7 @@ void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
if (dialog->sd_resp == NULL) {
buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested,
- dialog);
+ dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf);
if (!buf)
@@ -571,7 +1054,7 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested,
- dialog);
+ dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf);
if (!buf)
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 0e2eaf66..4213cf6d 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -13,8 +13,30 @@
(1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
#define ANQP_REQ_VENUE_NAME \
(1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_NETWORK_AUTH_TYPE \
+ (1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
#define ANQP_REQ_ROAMING_CONSORTIUM \
(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
+ (1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_NAI_REALM \
+ (1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
+#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
+ (1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_DOMAIN_NAME \
+ (1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_HS_CAPABILITY_LIST \
+ (0x10000 << HS20_STYPE_CAPABILITY_LIST)
+#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
+ (0x10000 << HS20_STYPE_OPERATOR_FRIENDLY_NAME)
+#define ANQP_REQ_WAN_METRICS \
+ (0x10000 << HS20_STYPE_WAN_METRICS)
+#define ANQP_REQ_CONNECTION_CAPABILITY \
+ (0x10000 << HS20_STYPE_CONNECTION_CAPABILITY)
+#define ANQP_REQ_NAI_HOME_REALM \
+ (0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
+#define ANQP_REQ_OPERATING_CLASS \
+ (0x10000 << HS20_STYPE_OPERATING_CLASS)
/* To account for latencies between hostapd and external ANQP processor */
#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 22c5e654..34292587 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -39,6 +39,7 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
extern int wpa_debug_level;
+extern struct wpa_driver_ops *wpa_drivers[];
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -98,7 +99,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
hostapd_update_wps(hapd);
if (hapd->conf->ssid.ssid_set &&
- hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
+ hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len)) {
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
/* try to continue */
@@ -113,9 +114,10 @@ int hostapd_reload_config(struct hostapd_iface *iface)
struct hostapd_config *newconf, *oldconf;
size_t j;
- if (iface->config_read_cb == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->config_read_cb == NULL)
return -1;
- newconf = iface->config_read_cb(iface->config_fname);
+ newconf = iface->interfaces->config_read_cb(iface->config_fname);
if (newconf == NULL)
return -1;
@@ -286,8 +288,9 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
*/
static void hostapd_cleanup(struct hostapd_data *hapd)
{
- if (hapd->iface->ctrl_iface_deinit)
- hapd->iface->ctrl_iface_deinit(hapd);
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->ctrl_iface_deinit)
+ hapd->iface->interfaces->ctrl_iface_deinit(hapd);
hostapd_free_hapd_data(hapd);
}
@@ -679,14 +682,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
set_ssid = 0;
conf->ssid.ssid_len = ssid_len;
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
- conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
}
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
- " and ssid '%s'",
+ " and ssid \"%s\"",
hapd->conf->iface, MAC2STR(hapd->own_addr),
- hapd->conf->ssid.ssid);
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
}
if (hostapd_setup_wpa_psk(conf)) {
@@ -696,7 +699,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
/* Set SSID for the kernel driver (to be used in beacon and probe
* response frames) */
- if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
+ if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
conf->ssid.ssid_len)) {
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
return -1;
@@ -770,8 +773,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
}
#endif /* CONFIG_INTERWORKING */
- if (hapd->iface->ctrl_iface_init &&
- hapd->iface->ctrl_iface_init(hapd)) {
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->ctrl_iface_init &&
+ hapd->iface->interfaces->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR, "Failed to setup control interface");
return -1;
}
@@ -1045,6 +1049,292 @@ void hostapd_interface_free(struct hostapd_iface *iface)
}
+#ifdef HOSTAPD
+
+void hostapd_interface_deinit_free(struct hostapd_iface *iface)
+{
+ const struct wpa_driver_ops *driver;
+ void *drv_priv;
+ if (iface == NULL)
+ return;
+ driver = iface->bss[0]->driver;
+ drv_priv = iface->bss[0]->drv_priv;
+ hostapd_interface_deinit(iface);
+ if (driver && driver->hapd_deinit && drv_priv)
+ driver->hapd_deinit(drv_priv);
+ hostapd_interface_free(iface);
+}
+
+
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
+{
+ if (hapd_iface->bss[0]->drv_priv != NULL) {
+ wpa_printf(MSG_ERROR, "Interface %s already enabled",
+ hapd_iface->conf->bss[0].iface);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Enable interface %s",
+ hapd_iface->conf->bss[0].iface);
+
+ if (hapd_iface->interfaces == NULL ||
+ hapd_iface->interfaces->driver_init == NULL ||
+ hapd_iface->interfaces->driver_init(hapd_iface) ||
+ hostapd_setup_interface(hapd_iface)) {
+ hostapd_interface_deinit_free(hapd_iface);
+ return -1;
+ }
+ return 0;
+}
+
+
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
+{
+ size_t j;
+
+ wpa_printf(MSG_DEBUG, "Reload interface %s",
+ hapd_iface->conf->bss[0].iface);
+ for (j = 0; j < hapd_iface->num_bss; j++) {
+ hostapd_flush_old_stations(hapd_iface->bss[j],
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+#ifndef CONFIG_NO_RADIUS
+ /* TODO: update dynamic data based on changed configuration
+ * items (e.g., open/close sockets, etc.) */
+ radius_client_flush(hapd_iface->bss[j]->radius, 0);
+#endif /* CONFIG_NO_RADIUS */
+
+ hostapd_reload_bss(hapd_iface->bss[j]);
+ }
+ return 0;
+}
+
+
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
+{
+ size_t j;
+ struct hostapd_bss_config *bss = hapd_iface->bss[0]->conf;
+ const struct wpa_driver_ops *driver;
+ void *drv_priv;
+
+ if (hapd_iface == NULL)
+ return -1;
+ driver = hapd_iface->bss[0]->driver;
+ drv_priv = hapd_iface->bss[0]->drv_priv;
+
+ /* whatever hostapd_interface_deinit does */
+ for (j = 0; j < hapd_iface->num_bss; j++) {
+ struct hostapd_data *hapd = hapd_iface->bss[j];
+ hostapd_free_stas(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
+ hostapd_free_hapd_data(hapd);
+ }
+
+ if (driver && driver->hapd_deinit && drv_priv) {
+ driver->hapd_deinit(drv_priv);
+ hapd_iface->bss[0]->drv_priv = NULL;
+ }
+
+ /* From hostapd_cleanup_iface: These were initialized in
+ * hostapd_setup_interface and hostapd_setup_interface_complete
+ */
+ hostapd_cleanup_iface_partial(hapd_iface);
+ bss->wpa = 0;
+ bss->wpa_key_mgmt = -1;
+ bss->wpa_pairwise = -1;
+
+ wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+ return 0;
+}
+
+
+static struct hostapd_iface *
+hostapd_iface_alloc(struct hapd_interfaces *interfaces)
+{
+ struct hostapd_iface **iface, *hapd_iface;
+
+ iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
+ sizeof(struct hostapd_iface *));
+ if (iface == NULL)
+ return NULL;
+ interfaces->iface = iface;
+ hapd_iface = interfaces->iface[interfaces->count] =
+ os_zalloc(sizeof(*hapd_iface));
+ if (hapd_iface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+ "the interface", __func__);
+ return NULL;
+ }
+ interfaces->count++;
+ hapd_iface->interfaces = interfaces;
+
+ return hapd_iface;
+}
+
+
+static struct hostapd_config *
+hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
+ const char *ctrl_iface)
+{
+ struct hostapd_bss_config *bss;
+ struct hostapd_config *conf;
+
+ /* Allocates memory for bss and conf */
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+ "configuration", __func__);
+ return NULL;
+ }
+
+ conf->driver = wpa_drivers[0];
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ bss = conf->last_bss = conf->bss;
+
+ os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+ bss->ctrl_interface = os_strdup(ctrl_iface);
+ if (bss->ctrl_interface == NULL) {
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ /* Reading configuration file skipped, will be done in SET!
+ * From reading the configuration till the end has to be done in
+ * SET
+ */
+ return conf;
+}
+
+
+static struct hostapd_iface * hostapd_data_alloc(
+ struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+{
+ size_t i;
+ struct hostapd_iface *hapd_iface =
+ interfaces->iface[interfaces->count - 1];
+ struct hostapd_data *hapd;
+
+ hapd_iface->conf = conf;
+ hapd_iface->num_bss = conf->num_bss;
+
+ hapd_iface->bss = os_zalloc(conf->num_bss *
+ sizeof(struct hostapd_data *));
+ if (hapd_iface->bss == NULL)
+ return NULL;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ hapd = hapd_iface->bss[i] =
+ hostapd_alloc_bss_data(hapd_iface, conf,
+ &conf->bss[i]);
+ if (hapd == NULL)
+ return NULL;
+ hapd->msg_ctx = hapd;
+ }
+
+ hapd_iface->interfaces = interfaces;
+
+ return hapd_iface;
+}
+
+
+int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+ struct hostapd_config *conf = NULL;
+ struct hostapd_iface *hapd_iface = NULL;
+ char *ptr;
+ size_t i;
+
+ ptr = os_strchr(buf, ' ');
+ if (ptr == NULL)
+ return -1;
+ *ptr++ = '\0';
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+ buf)) {
+ wpa_printf(MSG_INFO, "Cannot add interface - it "
+ "already exists");
+ return -1;
+ }
+ }
+
+ hapd_iface = hostapd_iface_alloc(interfaces);
+ if (hapd_iface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+ "for interface", __func__);
+ goto fail;
+ }
+
+ conf = hostapd_config_alloc(interfaces, buf, ptr);
+ if (conf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+ "for configuration", __func__);
+ goto fail;
+ }
+
+ hapd_iface = hostapd_data_alloc(interfaces, conf);
+ if (hapd_iface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+ "for hostapd", __func__);
+ goto fail;
+ }
+
+ if (hapd_iface->interfaces &&
+ hapd_iface->interfaces->ctrl_iface_init &&
+ hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
+ wpa_printf(MSG_ERROR, "%s: Failed to setup control "
+ "interface", __func__);
+ goto fail;
+ }
+ wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+ return 0;
+
+fail:
+ if (conf)
+ hostapd_config_free(conf);
+ if (hapd_iface) {
+ os_free(hapd_iface->bss[interfaces->count]);
+ os_free(hapd_iface);
+ }
+ return -1;
+}
+
+
+int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+ struct hostapd_iface *hapd_iface;
+ size_t i, k = 0;
+
+ for (i = 0; i < interfaces->count; i++) {
+ hapd_iface = interfaces->iface[i];
+ if (hapd_iface == NULL)
+ return -1;
+ if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+ wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+ hostapd_interface_deinit_free(hapd_iface);
+ k = i;
+ while (k < (interfaces->count - 1)) {
+ interfaces->iface[k] =
+ interfaces->iface[k + 1];
+ k++;
+ }
+ interfaces->count--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+#endif /* HOSTAPD */
+
+
/**
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
* @hapd: Pointer to BSS data
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f7ed3110..71f476c0 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -23,8 +23,22 @@ struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
+struct hostapd_iface;
+
struct hapd_interfaces {
+ int (*reload_config)(struct hostapd_iface *iface);
+ struct hostapd_config * (*config_read_cb)(const char *config_fname);
+ int (*ctrl_iface_init)(struct hostapd_data *hapd);
+ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
+ int (*for_each_interface)(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
+ int (*driver_init)(struct hostapd_iface *iface);
+
size_t count;
+ int global_ctrl_sock;
+ char *global_iface_path;
+ char *global_iface_name;
struct hostapd_iface **iface;
};
@@ -182,8 +196,6 @@ struct hostapd_data {
struct hostapd_iface {
struct hapd_interfaces *interfaces;
void *owner;
- int (*reload_config)(struct hostapd_iface *iface);
- struct hostapd_config * (*config_read_cb)(const char *config_fname);
char *config_fname;
struct hostapd_config *conf;
@@ -241,13 +253,6 @@ struct hostapd_iface {
u16 ht_op_mode;
void (*scan_cb)(struct hostapd_iface *iface);
-
- int (*ctrl_iface_init)(struct hostapd_data *hapd);
- void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-
- int (*for_each_interface)(struct hapd_interfaces *interfaces,
- int (*cb)(struct hostapd_iface *iface,
- void *ctx), void *ctx);
};
/* hostapd.c */
@@ -265,6 +270,12 @@ void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
+void hostapd_interface_deinit_free(struct hostapd_iface *iface);
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
+int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
new file mode 100644
index 00000000..45d518bc
--- /dev/null
+++ b/src/ap/hs20.c
@@ -0,0 +1,31 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * 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 "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "hs20.h"
+
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
+{
+ if (!hapd->conf->hs20)
+ return eid;
+ *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+ *eid++ = 5;
+ WPA_PUT_BE24(eid, OUI_WFA);
+ eid += 3;
+ *eid++ = HS20_INDICATION_OUI_TYPE;
+ /* Hotspot Configuration: DGAF Enabled */
+ *eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
+ return eid;
+}
diff --git a/src/ap/hs20.h b/src/ap/hs20.h
new file mode 100644
index 00000000..98698ce2
--- /dev/null
+++ b/src/ap/hs20.h
@@ -0,0 +1,16 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * 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_H
+#define HS20_H
+
+struct hostapd_data;
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* HS20_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 76c42118..76aff775 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -138,7 +138,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
iface->num_rates = 0;
iface->current_rates =
- os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
+ os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
if (!iface->current_rates) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
"table.");
@@ -470,7 +470,7 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
affected_start, affected_end);
mode = iface->current_mode;
- params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
pos = 0;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 3996c90d..211ee1bc 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -311,6 +311,8 @@ static void handle_auth(struct hostapd_data *hapd,
int has_psk = 0;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
+ char *identity = NULL;
+ char *radius_cui = NULL;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
printf("handle_auth - too short payload (len=%lu)\n",
@@ -372,7 +374,7 @@ static void handle_auth(struct hostapd_data *hapd,
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
- psk, &has_psk);
+ psk, &has_psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -421,6 +423,11 @@ static void handle_auth(struct hostapd_data *hapd,
sta->psk = NULL;
}
+ sta->identity = identity;
+ identity = NULL;
+ sta->radius_cui = radius_cui;
+ radius_cui = NULL;
+
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
@@ -482,6 +489,9 @@ static void handle_auth(struct hostapd_data *hapd,
}
fail:
+ os_free(identity);
+ os_free(radius_cui);
+
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies, resp_ies_len);
}
@@ -576,35 +586,20 @@ static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (elems->supp_rates_len > sizeof(sta->supported_rates)) {
+ if (elems->supp_rates_len + elems->ext_supp_rates_len >
+ sizeof(sta->supported_rates)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "Invalid supported rates element length %d",
- elems->supp_rates_len);
+ "Invalid supported rates element length %d+%d",
+ elems->supp_rates_len,
+ elems->ext_supp_rates_len);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- os_memcpy(sta->supported_rates, elems->supp_rates,
- elems->supp_rates_len);
- sta->supported_rates_len = elems->supp_rates_len;
-
- if (elems->ext_supp_rates) {
- if (elems->supp_rates_len + elems->ext_supp_rates_len >
- sizeof(sta->supported_rates)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "Invalid supported rates element length"
- " %d+%d", elems->supp_rates_len,
- elems->ext_supp_rates_len);
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
-
- os_memcpy(sta->supported_rates + elems->supp_rates_len,
- elems->ext_supp_rates, elems->ext_supp_rates_len);
- sta->supported_rates_len += elems->ext_supp_rates_len;
- }
+ sta->supported_rates_len = merge_byte_arrays(
+ sta->supported_rates, sizeof(sta->supported_rates),
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
return WLAN_STATUS_SUCCESS;
}
@@ -648,6 +643,20 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
+ elems.vht_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
+ !(sta->flags & WLAN_STA_VHT)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Station does not support "
+ "mandatory VHT PHY - reject association");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_IEEE80211AC */
+
if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
wpa_ie = elems.rsn_ie;
wpa_ie_len = elems.rsn_ie_len;
@@ -771,7 +780,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211N
- if ((sta->flags & WLAN_STA_HT) &&
+ if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@@ -875,6 +884,11 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
p = hostapd_eid_ht_operation(hapd, p);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ p = hostapd_eid_vht_capabilities(hapd, p);
+ p = hostapd_eid_vht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
@@ -1337,7 +1351,10 @@ static void handle_action(struct hostapd_data *hapd,
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- hostapd_drv_send_mlme(hapd, resp, len, 0);
+ if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+ wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
+ "Action frame");
+ }
os_free(resp);
}
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 9993bee1..1e5800d0 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -56,6 +56,8 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_capab, size_t vht_capab_len);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 0c4c5f32..63ae3452 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,6 +22,7 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_11.h"
+#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#define RADIUS_ACL_TIMEOUT 30
@@ -37,6 +38,8 @@ struct hostapd_cached_radius_acl {
int vlan_id;
int has_psk;
u8 psk[PMK_LEN];
+ char *identity;
+ char *radius_cui;
};
@@ -51,6 +54,14 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
+{
+ os_free(e->identity);
+ os_free(e->radius_cui);
+ os_free(e);
+}
+
+
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
{
struct hostapd_cached_radius_acl *prev;
@@ -58,7 +69,7 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
while (acl_cache) {
prev = acl_cache;
acl_cache = acl_cache->next;
- os_free(prev);
+ hostapd_acl_cache_free_entry(prev);
}
}
@@ -66,35 +77,45 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk)
+ u8 *psk, int *has_psk, char **identity,
+ char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
os_get_time(&now);
- entry = hapd->acl_cache;
- while (entry) {
- if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
- if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
- return -1; /* entry has expired */
- if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- if (session_timeout)
- *session_timeout =
- entry->session_timeout;
- if (acct_interim_interval)
- *acct_interim_interval =
- entry->acct_interim_interval;
- if (vlan_id)
- *vlan_id = entry->vlan_id;
- if (psk)
- os_memcpy(psk, entry->psk, PMK_LEN);
- if (has_psk)
- *has_psk = entry->has_psk;
- return entry->accepted;
- }
+ for (entry = hapd->acl_cache; entry; entry = entry->next) {
+ if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
+ continue;
- entry = entry->next;
+ if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+ return -1; /* entry has expired */
+ if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+ if (session_timeout)
+ *session_timeout = entry->session_timeout;
+ if (acct_interim_interval)
+ *acct_interim_interval =
+ entry->acct_interim_interval;
+ if (vlan_id)
+ *vlan_id = entry->vlan_id;
+ if (psk)
+ os_memcpy(psk, entry->psk, PMK_LEN);
+ if (has_psk)
+ *has_psk = entry->has_psk;
+ if (identity) {
+ if (entry->identity)
+ *identity = os_strdup(entry->identity);
+ else
+ *identity = NULL;
+ }
+ if (radius_cui) {
+ if (entry->radius_cui)
+ *radius_cui = os_strdup(entry->radius_cui);
+ else
+ *radius_cui = NULL;
+ }
+ return entry->accepted;
}
return -1;
@@ -140,37 +161,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
- if (hapd->conf->own_ip_addr.af == AF_INET &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
- goto fail;
- }
-
-#ifdef CONFIG_IPV6
- if (hapd->conf->own_ip_addr.af == AF_INET6 &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
- goto fail;
- }
-#endif /* CONFIG_IPV6 */
-
- if (hapd->conf->nas_identifier &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
- (u8 *) hapd->conf->nas_identifier,
- os_strlen(hapd->conf->nas_identifier))) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
+ if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
+ NULL, msg) < 0)
goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
- goto fail;
- }
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(addr));
@@ -180,12 +173,6 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
- RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
- goto fail;
- }
-
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
@@ -215,12 +202,18 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @vlan_id: Buffer for returning VLAN ID
* @psk: Buffer for returning WPA PSK
* @has_psk: Buffer for indicating whether psk was filled
+ * @identity: Buffer for returning identity (from RADIUS)
+ * @radius_cui: Buffer for returning CUI (from RADIUS)
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ *
+ * The caller is responsible for freeing the returned *identity and *radius_cui
+ * values with os_free().
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk)
+ u8 *psk, int *has_psk, char **identity,
+ char **radius_cui)
{
if (session_timeout)
*session_timeout = 0;
@@ -232,6 +225,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
*has_psk = 0;
if (psk)
os_memset(psk, 0, PMK_LEN);
+ if (identity)
+ *identity = NULL;
+ if (radius_cui)
+ *radius_cui = NULL;
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
@@ -256,7 +253,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
- vlan_id, psk, has_psk);
+ vlan_id, psk, has_psk,
+ identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -268,6 +266,14 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
+ if (identity) {
+ os_free(*identity);
+ *identity = NULL;
+ }
+ if (radius_cui) {
+ os_free(*radius_cui);
+ *radius_cui = NULL;
+ }
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@@ -333,7 +339,7 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
tmp = entry;
entry = entry->next;
- os_free(tmp);
+ hostapd_acl_cache_free_entry(tmp);
continue;
}
@@ -450,6 +456,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
int passphraselen;
char *passphrase;
+ u8 *buf;
+ size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
@@ -491,6 +499,19 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
os_free(passphrase);
}
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+ &buf, &len, NULL) == 0) {
+ cache->identity = os_zalloc(len + 1);
+ if (cache->identity)
+ os_memcpy(cache->identity, buf, len);
+ }
+ if (radius_msg_get_attr_ptr(
+ msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+ cache->radius_cui = os_zalloc(len + 1);
+ if (cache->radius_cui)
+ os_memcpy(cache->radius_cui, buf, len);
+ }
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->has_psk)
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b8a4c138..0e8d1cb1 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -19,7 +19,8 @@ enum {
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk);
+ u8 *psk, int *has_psk, char **identity,
+ char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 3ad33c89..7599ef8d 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -61,12 +61,48 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
oper = (struct ieee80211_vht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
+ /*
+ * center freq = 5 GHz + (5 * index)
+ * So index 42 gives center freq 5.210 GHz
+ * which is channel 42 in 5G band
+ */
+ oper->vht_op_info_chan_center_freq_seg0_idx =
+ hapd->iconf->vht_oper_centr_freq_seg0_idx;
+
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
/* VHT Basic MCS set comes from hw */
/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
- oper->vht_basic_mcs_set = 0xfffc;
+ oper->vht_basic_mcs_set = host_to_le16(0xfffc);
pos += sizeof(*oper);
return pos;
}
+
+
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_capab, size_t vht_capab_len)
+{
+ /* Disable VHT caps for STAs associated to no-VHT BSSes. */
+ if (!vht_capab ||
+ vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+ hapd->conf->disable_11ac) {
+ sta->flags &= ~WLAN_STA_VHT;
+ os_free(sta->vht_capabilities);
+ sta->vht_capabilities = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (sta->vht_capabilities == NULL) {
+ sta->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (sta->vht_capabilities == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_VHT;
+ os_memcpy(sta->vht_capabilities, vht_capab,
+ sizeof(struct ieee80211_vht_capabilities));
+
+ return WLAN_STATUS_SUCCESS;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 9bbd1ff2..c4d3da82 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -126,7 +126,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
hdr = (struct ieee802_1x_hdr *) buf;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
key->type = EAPOL_KEY_TYPE_RC4;
- key->key_length = htons(key_len);
+ WPA_PUT_BE16(key->key_length, key_len);
wpa_get_ntp_timestamp(key->replay_counter);
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
@@ -409,97 +409,163 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
}
-static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
- struct sta_info *sta,
- const u8 *eap, size_t len)
+static int add_common_radius_sta_attr(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg)
{
- struct radius_msg *msg;
char buf[128];
- struct eapol_state_machine *sm = sta->eapol_sm;
- struct hostapd_radius_attr *attr;
-
- if (sm == NULL)
- return;
- ieee802_1x_learn_identity(hapd, sm, eap, len);
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_PORT) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-Port");
+ return -1;
+ }
- wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
- "packet");
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(sta->addr));
+ buf[sizeof(buf) - 1] = '\0';
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
+ return -1;
+ }
- sm->radius_identifier = radius_client_get_id(hapd->radius);
- msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
- sm->radius_identifier);
- if (msg == NULL) {
- printf("Could not create net RADIUS packet\n");
- return;
+ if (sta->flags & WLAN_STA_PREAUTH) {
+ os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
+ sizeof(buf));
+ } else {
+ os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+ radius_sta_rate(hapd, sta) / 2,
+ (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+ radius_mode_txt(hapd));
+ buf[sizeof(buf) - 1] = '\0';
+ }
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Connect-Info");
+ return -1;
}
- radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+ return 0;
+}
- if (sm->identity &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
- sm->identity, sm->identity_len)) {
- printf("Could not add User-Name\n");
- goto fail;
- }
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+int add_common_radius_attr(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ char buf[128];
+ struct hostapd_radius_attr *attr;
+
+ if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IP_ADDRESS) &&
hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
- printf("Could not add NAS-IP-Address\n");
- goto fail;
+ wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
+ return -1;
}
#ifdef CONFIG_IPV6
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
- printf("Could not add NAS-IPv6-Address\n");
- goto fail;
+ wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
+ return -1;
}
#endif /* CONFIG_IPV6 */
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IDENTIFIER) &&
hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
- printf("Could not add NAS-Identifier\n");
- goto fail;
- }
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_PORT) &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
- printf("Could not add NAS-Port\n");
- goto fail;
+ wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
+ return -1;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
+ MAC2STR(hapd->own_addr),
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
buf[sizeof(buf) - 1] = '\0';
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_CALLED_STATION_ID) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
- printf("Could not add Called-Station-Id\n");
- goto fail;
+ wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
+ return -1;
}
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
- MAC2STR(sta->addr));
- buf[sizeof(buf) - 1] = '\0';
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Calling-Station-Id\n");
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+ RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
+ return -1;
+ }
+
+ if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
+ return -1;
+
+ for (attr = req_attr; attr; attr = attr->next) {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS "
+ "attribute");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *eap, size_t len)
+{
+ struct radius_msg *msg;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ ieee802_1x_learn_identity(hapd, sm, eap, len);
+
+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
+ "packet");
+
+ sm->radius_identifier = radius_client_get_id(hapd->radius);
+ msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+ sm->radius_identifier);
+ if (msg == NULL) {
+ printf("Could not create net RADIUS packet\n");
+ return;
+ }
+
+ radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+ if (sm->identity &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+ sm->identity, sm->identity_len)) {
+ printf("Could not add User-Name\n");
goto fail;
}
+ if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
+ msg) < 0)
+ goto fail;
+
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
@@ -510,32 +576,6 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
goto fail;
}
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_PORT_TYPE) &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
- RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
- printf("Could not add NAS-Port-Type\n");
- goto fail;
- }
-
- if (sta->flags & WLAN_STA_PREAUTH) {
- os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
- sizeof(buf));
- } else {
- os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
- radius_sta_rate(hapd, sta) / 2,
- (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
- radius_mode_txt(hapd));
- buf[sizeof(buf) - 1] = '\0';
- }
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_CONNECT_INFO) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Connect-Info\n");
- goto fail;
- }
-
if (eap && !radius_msg_add_eap(msg, eap, len)) {
printf("Could not add EAP-Message\n");
goto fail;
@@ -577,17 +617,6 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
}
}
- for (attr = hapd->conf->radius_auth_req_attr; attr; attr = attr->next)
- {
- if (!radius_msg_add_attr(msg, attr->type,
- wpabuf_head(attr->val),
- wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
- goto fail;
- }
- }
-
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
goto fail;
@@ -693,7 +722,8 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
flags |= EAPOL_SM_FROM_PMKSA_CACHE;
}
return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
- sta->wps_ie, sta->p2p_ie, sta);
+ sta->wps_ie, sta->p2p_ie, sta,
+ sta->identity, sta->radius_cui);
}
@@ -1037,9 +1067,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta)
{
- 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;
@@ -1053,7 +1082,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
msg = sm->last_recv_radius;
- eap = radius_msg_get_eap(msg, &len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
@@ -1065,19 +1094,19 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
return;
}
- if (len < sizeof(*hdr)) {
+ if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "too short EAP packet "
"received from authentication server");
- os_free(eap);
+ wpabuf_free(eap);
sm->eap_if->aaaEapNoReq = TRUE;
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:
if (eap_type >= 0)
@@ -1112,7 +1141,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
sm->eap_if->aaaEapReq = TRUE;
wpabuf_free(sm->eap_if->aaaEapReqData);
- sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len);
+ sm->eap_if->aaaEapReqData = eap;
}
@@ -1177,7 +1206,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
if (count <= 0)
return;
- nclass = os_zalloc(count * sizeof(struct radius_attr_data));
+ nclass = os_calloc(count, sizeof(struct radius_attr_data));
if (nclass == NULL)
return;
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index f9b05caf..e1df9405 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,38 +14,8 @@ struct sta_info;
struct eapol_state_machine;
struct hostapd_config;
struct hostapd_bss_config;
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-/* RFC 3580, 4. RC4 EAPOL-Key Frame */
-
-struct ieee802_1x_eapol_key {
- u8 type;
- u16 key_length;
- u8 replay_counter[8]; /* does not repeat within the life of the keying
- * material used to encrypt the Key field;
- * 64-bit NTP timestamp MAY be used here */
- u8 key_iv[16]; /* cryptographically random number */
- u8 key_index; /* key flag in the most significant bit:
- * 0 = broadcast (default key),
- * 1 = unicast (key mapping key); key index is in the
- * 7 least significant bits */
- u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
- * MS-MPPE-Send-Key as the key */
-
- /* followed by key: if packet body length = 44 + key length, then the
- * key field (of key_length bytes) contains the key in encrypted form;
- * if packet body length = 44, key field is absent and key_length
- * represents the number of least significant octets from
- * MS-MPPE-Send-Key attribute to be used as the keying material;
- * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
+struct hostapd_radius_attr;
+struct radius_msg;
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
@@ -83,4 +53,9 @@ char *eap_type_text(u8 type);
const char *radius_mode_txt(struct hostapd_data *hapd);
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+int add_common_radius_attr(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg);
+
#endif /* IEEE802_1X_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 95b701cc..d61177fd 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -235,6 +235,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->ht_capabilities);
os_free(sta->psk);
+ os_free(sta->identity);
+ os_free(sta->radius_cui);
os_free(sta);
}
@@ -795,8 +797,9 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
ap_check_sa_query_timeout(hapd, sta))
return;
- nbuf = os_realloc(sta->sa_query_trans_id,
- (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
+ nbuf = os_realloc_array(sta->sa_query_trans_id,
+ sta->sa_query_count + 1,
+ WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (sta->sa_query_count == 0) {
@@ -818,9 +821,7 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
HOSTAPD_LEVEL_DEBUG,
"association SA Query attempt %d", sta->sa_query_count);
-#ifdef NEED_AP_MLME
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
-#endif /* NEED_AP_MLME */
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index cef428df..b3c57b43 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -28,6 +28,7 @@
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
#define WLAN_STA_WPS2 BIT(16)
#define WLAN_STA_GAS BIT(17)
+#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -96,7 +97,11 @@ struct sta_info {
int vlan_id;
u8 *psk; /* PSK from RADIUS authentication server */
+ char *identity; /* User-Name from RADIUS */
+ char *radius_cui; /* Chargeable-User-Identity from RADIUS */
+
struct ieee80211_ht_capabilities *ht_capabilities;
+ struct ieee80211_vht_capabilities *vht_capabilities;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 3e9fc081..931968c8 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -23,8 +23,8 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
{
struct hostapd_probereq_cb *n;
- n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) *
- sizeof(struct hostapd_probereq_cb));
+ n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1,
+ sizeof(struct hostapd_probereq_cb));
if (n == NULL)
return -1;
@@ -78,7 +78,8 @@ void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
struct prune_data data;
data.hapd = hapd;
data.addr = addr;
- if (hapd->iface->for_each_interface)
- hapd->iface->for_each_interface(hapd->iface->interfaces,
- prune_associations, &data);
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->for_each_interface)
+ hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, prune_associations, &data);
}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index f2f766f2..7b1a9e67 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -21,6 +21,7 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "vlan_init.h"
+#include "vlan_util.h"
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -335,7 +336,9 @@ static int br_getnumports(const char *br_name)
}
-static int vlan_rem(const char *if_name)
+#ifndef CONFIG_VLAN_NETLINK
+
+int vlan_rem(const char *if_name)
{
int fd;
struct vlan_ioctl_args if_request;
@@ -378,7 +381,7 @@ static int vlan_rem(const char *if_name)
returns 1 if the interface already exists
returns 0 otherwise
*/
-static int vlan_add(const char *if_name, int vid)
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int fd;
struct vlan_ioctl_args if_request;
@@ -474,6 +477,8 @@ static int vlan_set_name_type(unsigned int name_type)
return 0;
}
+#endif /* CONFIG_VLAN_NETLINK */
+
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
{
@@ -481,6 +486,7 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
char br_name[IFNAMSIZ];
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
@@ -496,13 +502,22 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
ifconfig_up(br_name);
if (tagged_interface) {
-
- if (!vlan_add(tagged_interface, vlan->vlan_id))
+ if (vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "%s.%d", tagged_interface,
+ vlan->vlan_id);
+ else
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "vlan%d", vlan->vlan_id);
+
+ ifconfig_up(tagged_interface);
+ if (!vlan_add(tagged_interface, vlan->vlan_id,
+ vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN;
- os_snprintf(vlan_ifname, sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
-
if (!br_addif(br_name, vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
@@ -527,6 +542,7 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
char br_name[IFNAMSIZ];
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
@@ -541,8 +557,16 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
br_delif(br_name, vlan->ifname);
if (tagged_interface) {
- os_snprintf(vlan_ifname, sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
+ if (vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "%s.%d", tagged_interface,
+ vlan->vlan_id);
+ else
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "vlan%d", vlan->vlan_id);
if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
ifconfig_down(vlan_ifname);
@@ -682,7 +706,12 @@ full_dynamic_vlan_init(struct hostapd_data *hapd)
if (priv == NULL)
return NULL;
- vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+#ifndef CONFIG_VLAN_NETLINK
+ vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+#endif /* CONFIG_VLAN_NETLINK */
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (priv->s < 0) {
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
new file mode 100644
index 00000000..cc54051b
--- /dev/null
+++ b/src/ap/vlan_util.c
@@ -0,0 +1,177 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "vlan_util.h"
+
+/*
+ * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
+ * tagged interface 'if_name'.
+ *
+ * returns -1 on error
+ * returns 1 if the interface already exists
+ * returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+ int ret = -1;
+ struct nl_sock *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *rlink = NULL;
+ int if_idx = 0;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
+ "vlan_if_name=%s)", if_name, vid, vlan_if_name);
+
+ if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ vlan_if_name);
+ return -1;
+ }
+
+ handle = nl_socket_alloc();
+ if (!handle) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+ goto vlan_add_error;
+ }
+
+ if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+ goto vlan_add_error;
+ }
+
+ if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+ cache = NULL;
+ wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+ goto vlan_add_error;
+ }
+
+ if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
+ /* link does not exist */
+ wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
+ if_name);
+ goto vlan_add_error;
+ }
+
+ if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
+ /* link does exist */
+ rtnl_link_put(rlink);
+ rlink = NULL;
+ wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
+ vlan_if_name);
+ ret = 1;
+ goto vlan_add_error;
+ }
+
+ rlink = rtnl_link_alloc();
+ if (!rlink) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
+ goto vlan_add_error;
+ }
+
+ if (rtnl_link_set_type(rlink, "vlan") < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
+ goto vlan_add_error;
+ }
+
+ rtnl_link_set_link(rlink, if_idx);
+ rtnl_link_set_name(rlink, vlan_if_name);
+
+ if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
+ goto vlan_add_error;
+ }
+
+ if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
+ "vlan %d on %s (%d)",
+ vlan_if_name, vid, if_name, if_idx);
+ goto vlan_add_error;
+ }
+
+ ret = 0;
+
+vlan_add_error:
+ if (rlink)
+ rtnl_link_put(rlink);
+ if (cache)
+ nl_cache_free(cache);
+ if (handle)
+ nl_socket_free(handle);
+ return ret;
+}
+
+
+int vlan_rem(const char *if_name)
+{
+ int ret = -1;
+ struct nl_sock *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *rlink = NULL;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
+
+ handle = nl_socket_alloc();
+ if (!handle) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+ goto vlan_rem_error;
+ }
+
+ if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+ goto vlan_rem_error;
+ }
+
+ if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+ cache = NULL;
+ wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+ goto vlan_rem_error;
+ }
+
+ if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
+ /* link does not exist */
+ wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
+ if_name);
+ goto vlan_rem_error;
+ }
+
+ if (rtnl_link_delete(handle, rlink) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
+ if_name);
+ goto vlan_rem_error;
+ }
+
+ ret = 0;
+
+vlan_rem_error:
+ if (rlink)
+ rtnl_link_put(rlink);
+ if (cache)
+ nl_cache_free(cache);
+ if (handle)
+ nl_socket_free(handle);
+ return ret;
+}
diff --git a/src/ap/vlan_util.h b/src/ap/vlan_util.h
new file mode 100644
index 00000000..bef5a16f
--- /dev/null
+++ b/src/ap/vlan_util.h
@@ -0,0 +1,15 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_UTIL_H
+#define VLAN_UTIL_H
+
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
+int vlan_rem(const char *if_name);
+
+#endif /* VLAN_UTIL_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
new file mode 100644
index 00000000..25944045
--- /dev/null
+++ b/src/ap/wnm_ap.c
@@ -0,0 +1,258 @@
+/*
+ * hostapd - WNM
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
+#include "wnm_ap.h"
+
+#define MAX_TFS_IE_LEN 1024
+
+#ifdef CONFIG_IEEE80211V
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+ u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+ return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+ u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+ return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.response */
+static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
+ const u8 *addr, u8 dialog_token,
+ u8 action_type, u16 intval)
+{
+ struct ieee80211_mgmt *mgmt;
+ int res;
+ size_t len;
+ size_t gtk_elem_len = 0;
+ size_t igtk_elem_len = 0;
+ struct wnm_sleep_element wnmsleep_ie;
+ u8 *wnmtfs_ie;
+ u8 wnmsleep_ie_len;
+ u16 wnmtfs_ie_len;
+ u8 *pos;
+ struct sta_info *sta;
+ enum wnm_oper tfs_oper = action_type == 0 ? WNM_SLEEP_TFS_RESP_IE_ADD :
+ WNM_SLEEP_TFS_RESP_IE_NONE;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+ return -EINVAL;
+ }
+
+ /* WNM-Sleep Mode IE */
+ os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element));
+ wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+ wnmsleep_ie.eid = WLAN_EID_WNMSLEEP;
+ wnmsleep_ie.len = wnmsleep_ie_len - 2;
+ wnmsleep_ie.action_type = action_type;
+ wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
+ wnmsleep_ie.intval = intval;
+
+ /* TFS IE(s) */
+ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+ if (wnmtfs_ie == NULL)
+ return -1;
+ if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len,
+ tfs_oper)) {
+ wnmtfs_ie_len = 0;
+ os_free(wnmtfs_ie);
+ wnmtfs_ie = NULL;
+ }
+
+#define MAX_GTK_SUBELEM_LEN 45
+#define MAX_IGTK_SUBELEM_LEN 26
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
+ MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+ if (mgmt == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+ "WNM-Sleep Response action frame");
+ return -1;
+ }
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, 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_resp.action = WNM_SLEEP_MODE_RESP;
+ mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
+ pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
+ /* add key data if MFP is enabled */
+ if (wpa_auth_uses_mfp(sta->wpa_sm) || action_type != 1){
+ mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
+ } else {
+ gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
+ pos += gtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
+ (int) gtk_elem_len);
+#ifdef CONFIG_IEEE80211W
+ res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
+ if (res < 0) {
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+ return -1;
+ }
+ igtk_elem_len = res;
+ pos += igtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
+ (int) igtk_elem_len);
+#endif /* CONFIG_IEEE80211W */
+
+ WPA_PUT_LE16((u8 *)
+ &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
+ gtk_elem_len + igtk_elem_len);
+ }
+ os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
+ /* copy TFS IE here */
+ pos += wnmsleep_ie_len;
+ os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+
+ len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
+ igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+
+ /* In driver, response frame should be forced to sent when STA is in
+ * PS mode */
+ res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+ mgmt->da, &mgmt->u.action.category, len);
+
+ if (!res) {
+ wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response "
+ "frame");
+
+ /* when entering wnmsleep
+ * 1. pause the node in driver
+ * 2. mark the node so that AP won't update GTK/IGTK during
+ * WNM Sleep
+ */
+ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
+ wnmsleep_ie.action_type == 0) {
+ hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
+ addr, NULL, NULL);
+ wpa_set_wnmsleep(sta->wpa_sm, 1);
+ }
+ /* when exiting wnmsleep
+ * 1. unmark the node
+ * 2. start GTK/IGTK update if MFP is not used
+ * 3. unpause the node in driver
+ */
+ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
+ wnmsleep_ie.action_type == 1) {
+ wpa_set_wnmsleep(sta->wpa_sm, 0);
+ hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
+ addr, NULL, NULL);
+ if (wpa_auth_uses_mfp(sta->wpa_sm) && action_type == 1)
+ wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
+ }
+ } else
+ wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame");
+
+#undef MAX_GTK_SUBELEM_LEN
+#undef MAX_IGTK_SUBELEM_LEN
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+ return res;
+}
+
+
+static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *frm, int len)
+{
+ /*
+ * Action [1] | Dialog Token [1] | WNM-Sleep Mode IE |
+ * TFS Response IE
+ */
+ u8 *pos = (u8 *) frm; /* point to action field */
+ u8 dialog_token = pos[1];
+ struct wnm_sleep_element *wnmsleep_ie = NULL;
+ /* multiple TFS Req IE (assuming consecutive) */
+ u8 *tfsreq_ie_start = NULL;
+ u8 *tfsreq_ie_end = NULL;
+ u16 tfsreq_ie_len = 0;
+
+ pos += 1 + 1;
+ while (pos - frm < len - 1) {
+ u8 ie_len = *(pos+1);
+ if (*pos == WLAN_EID_WNMSLEEP)
+ wnmsleep_ie = (struct wnm_sleep_element *)pos;
+ else if (*pos == WLAN_EID_TFS_REQ) {
+ if (!tfsreq_ie_start)
+ tfsreq_ie_start = pos;
+ tfsreq_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->action_type == 0 && tfsreq_ie_start &&
+ tfsreq_ie_end && tfsreq_ie_end - tfsreq_ie_start >= 0) {
+ tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
+ tfsreq_ie_start;
+ wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
+ /* pass the TFS Req IE(s) to driver for processing */
+ if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+ &tfsreq_ie_len,
+ WNM_SLEEP_TFS_REQ_IE_SET))
+ wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE");
+ }
+
+ ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
+ wnmsleep_ie->action_type,
+ wnmsleep_ie->intval);
+
+ if (wnmsleep_ie->action_type == 1) {
+ /* clear the tfs after sending the resp frame */
+ ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+ &tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
+ }
+}
+
+
+void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action)
+{
+ u8 *pos = (u8 *) action->data + 1; /* point to the action field */
+ u8 act = *pos;
+
+ switch (act) {
+ case WNM_SLEEP_MODE_REQ:
+ ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
+ action->len);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif /* CONFIG_IEEE80211V */
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
new file mode 100644
index 00000000..ab7c4f1c
--- /dev/null
+++ b/src/ap/wnm_ap.h
@@ -0,0 +1,17 @@
+/*
+ * 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_AP_H
+#define WNM_AP_H
+
+struct rx_action;
+
+void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action);
+
+#endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 1d942a44..3203d4fb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -284,6 +284,9 @@ static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
case WPA_CIPHER_CCMP:
group->GTK_len = 16;
break;
+ case WPA_CIPHER_GCMP:
+ group->GTK_len = 16;
+ break;
case WPA_CIPHER_TKIP:
group->GTK_len = 32;
break;
@@ -849,7 +852,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
msg == GROUP_2) {
u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
- if (sm->pairwise == WPA_CIPHER_CCMP) {
+ if (sm->pairwise == WPA_CIPHER_CCMP ||
+ sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
@@ -865,7 +869,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
"did not use HMAC-SHA1-AES "
- "with CCMP");
+ "with CCMP/GCMP");
return;
}
}
@@ -1240,7 +1244,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
version = force_version;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
- else if (sm->pairwise == WPA_CIPHER_CCMP)
+ else if (sm->pairwise != WPA_CIPHER_TKIP)
version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1291,6 +1295,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
case WPA_CIPHER_CCMP:
WPA_PUT_BE16(key->key_length, 16);
break;
+ case WPA_CIPHER_GCMP:
+ WPA_PUT_BE16(key->key_length, 16);
+ break;
case WPA_CIPHER_TKIP:
WPA_PUT_BE16(key->key_length, 32);
break;
@@ -1538,6 +1545,8 @@ static enum wpa_alg wpa_alg_enum(int alg)
switch (alg) {
case WPA_CIPHER_CCMP:
return WPA_ALG_CCMP;
+ case WPA_CIPHER_GCMP:
+ return WPA_ALG_GCMP;
case WPA_CIPHER_TKIP:
return WPA_ALG_TKIP;
case WPA_CIPHER_WEP104:
@@ -1773,7 +1782,7 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
+ size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
@@ -1898,6 +1907,14 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
os_memset(igtk.pn, 0, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use of
+ * IGTK in the BSS.
+ */
+ if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+ return pos;
+ }
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
(const u8 *) &igtk, sizeof(igtk), NULL, 0);
@@ -1922,7 +1939,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
@@ -1960,6 +1977,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+ return;
+ gtk = dummy_gtk;
+ }
keyidx = gsm->GN;
_rsc = rsc;
encr = 1;
@@ -2076,6 +2102,9 @@ SM_STATE(WPA_PTK, PTKINITDONE)
if (sm->pairwise == WPA_CIPHER_TKIP) {
alg = WPA_ALG_TKIP;
klen = 32;
+ } else if (sm->pairwise == WPA_CIPHER_GCMP) {
+ alg = WPA_ALG_GCMP;
+ klen = 16;
} else {
alg = WPA_ALG_CCMP;
klen = 16;
@@ -2256,6 +2285,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
struct wpa_group *gsm = sm->group;
u8 *kde, *pos, hdr[2];
size_t kde_len;
+ u8 *gtk, dummy_gtk[32];
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
@@ -2276,6 +2306,16 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 1/2 msg of Group Key Handshake");
+ gtk = gsm->GTK[gsm->GN - 1];
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+ return;
+ gtk = dummy_gtk;
+ }
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm);
@@ -2287,10 +2327,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
hdr[0] = gsm->GN & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
- gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
} else {
- kde = gsm->GTK[gsm->GN - 1];
+ kde = gtk;
pos = kde + gsm->GTK_len;
}
@@ -2416,6 +2456,9 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
{
+ if (ctx != NULL && ctx != sm->group)
+ return 0;
+
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
@@ -2433,6 +2476,12 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
"marking station for GTK rekeying");
}
+#ifdef CONFIG_IEEE80211V
+ /* Do not rekey GTK/IGTK when STA is in wnmsleep */
+ if (sm->is_wnmsleep)
+ return 0;
+#endif /* CONFIG_IEEE80211V */
+
sm->group->GKeyDoneStations++;
sm->GUpdateStationKeys = TRUE;
@@ -2441,6 +2490,132 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
}
+#ifdef CONFIG_IEEE80211V
+/* update GTK when exiting wnmsleep mode */
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
+{
+ if (sm->is_wnmsleep)
+ return;
+
+ wpa_group_update_sta(sm, NULL);
+}
+
+
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
+{
+ sm->is_wnmsleep = !!flag;
+}
+
+
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ u8 *subelem;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len, pad_len;
+ const u8 *key;
+ size_t key_len;
+ u8 keybuf[32];
+
+ /* GTK subslement */
+ key_len = gsm->GTK_len;
+ if (key_len > sizeof(keybuf))
+ return 0;
+
+ /*
+ * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
+ * than 16 bytes.
+ */
+ pad_len = key_len % 8;
+ if (pad_len)
+ pad_len = 8 - pad_len;
+ if (key_len + pad_len < 16)
+ pad_len += 8;
+ if (pad_len) {
+ os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ os_memset(keybuf + key_len, 0, pad_len);
+ keybuf[key_len] = 0xdd;
+ key_len += pad_len;
+ key = keybuf;
+ } else
+ key = gsm->GTK[gsm->GN - 1];
+
+ /*
+ * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+ * Key[5..32] | 8 padding.
+ */
+ subelem_len = 13 + key_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return 0;
+
+ subelem[0] = WNM_SLEEP_SUBELEM_GTK;
+ subelem[1] = 11 + key_len + 8;
+ /* Key ID in B0-B1 of Key Info */
+ WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
+ subelem[4] = gsm->GTK_len;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5) != 0)
+ {
+ os_free(subelem);
+ return 0;
+ }
+ if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
+ os_free(subelem);
+ return 0;
+ }
+
+ os_memcpy(pos, subelem, subelem_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext GTK",
+ gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ os_free(subelem);
+
+ return subelem_len;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ u8 *subelem, *ptr;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+
+ /* IGTK subelement
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] |
+ * Key[16] | 8 padding */
+ subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return 0;
+
+ ptr = subelem;
+ *ptr++ = WNM_SLEEP_SUBELEM_IGTK;
+ *ptr++ = subelem_len - 2;
+ WPA_PUT_LE16(ptr, gsm->GN_igtk);
+ ptr += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, ptr) != 0) {
+ os_free(subelem);
+ return 0;
+ }
+ ptr += 6;
+ if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+ gsm->IGTK[gsm->GN_igtk - 4], ptr)) {
+ os_free(subelem);
+ return -1;
+ }
+
+ os_memcpy(pos, subelem, subelem_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext IGTK",
+ gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ os_free(subelem);
+
+ return subelem_len;
+}
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211V */
+
+
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
@@ -2470,7 +2645,7 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
- wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
+ wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
group->GKeyDoneStations);
}
@@ -2627,6 +2802,8 @@ static int wpa_cipher_bits(int cipher)
switch (cipher) {
case WPA_CIPHER_CCMP:
return 128;
+ case WPA_CIPHER_GCMP:
+ return 128;
case WPA_CIPHER_TKIP:
return 256;
case WPA_CIPHER_WEP104:
@@ -2758,6 +2935,8 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
} else if (sm->wpa == WPA_VERSION_WPA2) {
if (sm->pairwise == WPA_CIPHER_CCMP)
pairwise = RSN_CIPHER_SUITE_CCMP;
+ else if (sm->pairwise == WPA_CIPHER_GCMP)
+ pairwise = RSN_CIPHER_SUITE_GCMP;
else if (sm->pairwise == WPA_CIPHER_TKIP)
pairwise = RSN_CIPHER_SUITE_TKIP;
else if (sm->pairwise == WPA_CIPHER_WEP104)
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index a07779fa..91ba4991 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -158,6 +158,8 @@ struct wpa_auth_config {
int pmk_r1_push;
int ft_over_ds;
#endif /* CONFIG_IEEE80211R */
+ int disable_gtk;
+ int ap_mlme;
};
typedef enum {
@@ -196,6 +198,8 @@ struct wpa_auth_callbacks {
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
+ int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
+ size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
};
@@ -278,4 +282,13 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211V
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211V */
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index d2ec0886..9f7cdae3 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -52,6 +52,19 @@ wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
}
+static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr,
+ u8 *tspec_ie, size_t tspec_ielen)
+{
+ if (wpa_auth->cb.add_tspec == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
+ return -1;
+ }
+ return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
+ tspec_ielen);
+}
+
+
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
@@ -471,7 +484,8 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
#endif /* CONFIG_IEEE80211W */
-static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
+static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
+ u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len)
{
struct ieee802_11_elems parse;
@@ -504,7 +518,7 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
}
#ifdef NEED_AP_MLME
- if (parse.wmm_tspec) {
+ if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
struct wmm_tspec_element *tspec;
int res;
@@ -541,13 +555,35 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
}
#endif /* NEED_AP_MLME */
+ if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
+ struct wmm_tspec_element *tspec;
+ int res;
+
+ tspec = (struct wmm_tspec_element *) pos;
+ os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+ res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
+ sizeof(*tspec));
+ if (res >= 0) {
+ if (res)
+ rdie->status_code = host_to_le16(res);
+ else {
+ /* TSPEC accepted; include updated TSPEC in
+ * response */
+ rdie->descr_count = 1;
+ pos += sizeof(*tspec);
+ }
+ return pos;
+ }
+ }
+
wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
return pos;
}
-static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
+static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
+ const u8 *ric, size_t ric_len)
{
const u8 *rpos, *start;
const struct rsn_rdie *rdie;
@@ -569,7 +605,7 @@ static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
break;
rpos += 2 + rpos[1];
}
- pos = wpa_ft_process_rdie(pos, end, rdie->id,
+ pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
rdie->descr_count,
start, rpos - start);
}
@@ -678,7 +714,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
ric_start = pos;
if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
- pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len);
+ pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
+ parse.ric_len);
if (auth_alg == WLAN_AUTH_FT)
_ftie->mic_control[1] +=
ieee802_11_ie_count(ric_start,
@@ -723,6 +760,9 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
} else if (sm->pairwise == WPA_CIPHER_CCMP) {
alg = WPA_ALG_CCMP;
klen = 16;
+ } else if (sm->pairwise == WPA_CIPHER_GCMP) {
+ alg = WPA_ALG_GCMP;
+ klen = 16;
} else {
wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
"PTK configuration", sm->pairwise);
@@ -845,7 +885,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48;
+ ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name,
(u8 *) &sm->PTK, ptk_len, ptk_name);
@@ -1061,8 +1101,16 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
if (os_memcmp(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+ wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
+ MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
+ parse.mdie - 2, parse.mdie_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
+ parse.ftie - 2, parse.ftie_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
+ parse.rsn - 2, parse.rsn_len + 2);
return WLAN_STATUS_INVALID_FTIE;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 3e5ac1d8..bdc89e4f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -70,6 +70,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->pmk_r1_push = conf->pmk_r1_push;
wconf->ft_over_ds = conf->ft_over_ds;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_HS20
+ wconf->disable_gtk = conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
}
@@ -181,9 +184,15 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
- if (sta && sta->psk)
- return sta->psk;
- return hostapd_get_psk(hapd->conf, addr, prev_psk);
+ const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+ /*
+ * This is about to iterate over all psks, prev_psk gives the last
+ * returned psk which should not be returned again.
+ * logic list (all hostapd_get_psk; sta->psk)
+ */
+ if (sta && sta->psk && !psk && sta->psk != prev_psk)
+ psk = sta->psk;
+ return psk;
}
@@ -294,12 +303,13 @@ static int hostapd_wpa_auth_for_each_auth(
{
struct hostapd_data *hapd = ctx;
struct wpa_auth_iface_iter_data data;
- if (hapd->iface->for_each_interface == NULL)
+ if (hapd->iface->interfaces == NULL ||
+ hapd->iface->interfaces->for_each_interface == NULL)
return -1;
data.cb = cb;
data.cb_ctx = cb_ctx;
- return hapd->iface->for_each_interface(hapd->iface->interfaces,
- wpa_auth_iface_iter, &data);
+ return hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, wpa_auth_iface_iter, &data);
}
@@ -351,16 +361,17 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
int ret;
#ifdef CONFIG_IEEE80211R
- if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
+ if (proto == ETH_P_RRB && hapd->iface->interfaces &&
+ hapd->iface->interfaces->for_each_interface) {
int res;
struct wpa_auth_ft_iface_iter_data idata;
idata.src_hapd = hapd;
idata.dst = dst;
idata.data = data;
idata.data_len = data_len;
- res = hapd->iface->for_each_interface(hapd->iface->interfaces,
- hostapd_wpa_auth_ft_iter,
- &idata);
+ res = hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, hostapd_wpa_auth_ft_iter,
+ &idata);
if (res == 1)
return data_len;
}
@@ -425,6 +436,9 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+ return NULL;
+
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
@@ -458,6 +472,14 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
len - sizeof(*ethhdr));
}
+
+static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
+ u8 *tspec_ie, size_t tspec_ielen)
+{
+ struct hostapd_data *hapd = ctx;
+ return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
+}
+
#endif /* CONFIG_IEEE80211R */
@@ -471,6 +493,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
hostapd_wpa_auth_conf(hapd->conf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
+ _conf.ap_mlme = 1;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = hapd;
cb.logger = hostapd_wpa_auth_logger;
@@ -489,6 +513,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
cb.add_sta = hostapd_wpa_auth_add_sta;
+ cb.add_tspec = hostapd_wpa_auth_add_tspec;
#endif /* CONFIG_IEEE80211R */
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
if (hapd->wpa_auth == NULL) {
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index b2235768..d5cf2c50 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -87,6 +87,9 @@ struct wpa_state_machine {
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211V
+ unsigned int is_wnmsleep:1;
+#endif /* CONFIG_IEEE80211V */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index f6871823..b88b80ac 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -123,6 +123,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
if (conf->wpa_group == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ } else if (conf->wpa_group == WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
@@ -153,6 +155,11 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+ if (conf->rsn_pairwise & WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
pos += RSN_SELECTOR_LEN;
@@ -453,6 +460,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = RSN_CIPHER_SUITE_CCMP;
if (data.pairwise_cipher & WPA_CIPHER_CCMP)
selector = RSN_CIPHER_SUITE_CCMP;
+ else if (data.pairwise_cipher & WPA_CIPHER_GCMP)
+ selector = RSN_CIPHER_SUITE_GCMP;
else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
selector = RSN_CIPHER_SUITE_TKIP;
else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
@@ -466,6 +475,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = RSN_CIPHER_SUITE_CCMP;
if (data.group_cipher & WPA_CIPHER_CCMP)
selector = RSN_CIPHER_SUITE_CCMP;
+ else if (data.group_cipher & WPA_CIPHER_GCMP)
+ selector = RSN_CIPHER_SUITE_GCMP;
else if (data.group_cipher & WPA_CIPHER_TKIP)
selector = RSN_CIPHER_SUITE_TKIP;
else if (data.group_cipher & WPA_CIPHER_WEP104)
@@ -607,6 +618,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
if (ciphers & WPA_CIPHER_CCMP)
sm->pairwise = WPA_CIPHER_CCMP;
+ else if (ciphers & WPA_CIPHER_GCMP)
+ sm->pairwise = WPA_CIPHER_GCMP;
else
sm->pairwise = WPA_CIPHER_TKIP;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 07ce06c1..5e44c72c 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -13,7 +13,6 @@
#include "utils/uuid.h"
#include "crypto/dh_groups.h"
#include "crypto/dh_group5.h"
-#include "crypto/random.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -77,10 +76,11 @@ static int hostapd_wps_for_each(struct hostapd_data *hapd,
struct wps_for_each_data data;
data.func = func;
data.ctx = ctx;
- if (iface->for_each_interface == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->for_each_interface == NULL)
return wps_for_each(iface, &data);
- return iface->for_each_interface(iface->interfaces, wps_for_each,
- &data);
+ return iface->interfaces->for_each_interface(iface->interfaces,
+ wps_for_each, &data);
}
@@ -257,7 +257,8 @@ static void wps_reload_config(void *eloop_data, void *user_ctx)
struct hostapd_iface *iface = eloop_data;
wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
- if (iface->reload_config(iface) < 0) {
+ if (iface->interfaces == NULL ||
+ iface->interfaces->reload_config(iface) < 0) {
wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
"configuration");
}
@@ -344,6 +345,8 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
}
hapd->wps->wps_state = WPS_STATE_CONFIGURED;
+ if (hapd->iface->config_fname == NULL)
+ return 0;
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
@@ -371,10 +374,17 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "wps_state=2\n");
- fprintf(nconf, "ssid=");
- for (i = 0; i < cred->ssid_len; i++)
- fputc(cred->ssid[i], nconf);
- fprintf(nconf, "\n");
+ if (is_hex(cred->ssid, cred->ssid_len)) {
+ fprintf(nconf, "ssid2=");
+ for (i = 0; i < cred->ssid_len; i++)
+ fprintf(nconf, "%02x", cred->ssid[i]);
+ fprintf(nconf, "\n");
+ } else {
+ fprintf(nconf, "ssid=");
+ for (i = 0; i < cred->ssid_len; i++)
+ fputc(cred->ssid[i], nconf);
+ fprintf(nconf, "\n");
+ }
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
@@ -464,6 +474,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
multi_bss = 1;
if (!multi_bss &&
(str_starts(buf, "ssid=") ||
+ str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") ||
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
@@ -710,10 +721,12 @@ static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
static const u8 * get_own_uuid(struct hostapd_iface *iface)
{
const u8 *uuid;
- if (iface->for_each_interface == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->for_each_interface == NULL)
return NULL;
uuid = NULL;
- iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid);
+ iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
+ &uuid);
return uuid;
}
@@ -729,10 +742,11 @@ static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
static int interface_count(struct hostapd_iface *iface)
{
int count = 0;
- if (iface->for_each_interface == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->for_each_interface == NULL)
return 0;
- iface->for_each_interface(iface->interfaces, count_interface_cb,
- &count);
+ iface->interfaces->for_each_interface(iface->interfaces,
+ count_interface_cb, &count);
return count;
}
diff --git a/src/common/defs.h b/src/common/defs.h
index f057ffe3..db29b5df 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -26,6 +26,7 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#ifdef CONFIG_IEEE80211W
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#endif /* CONFIG_IEEE80211W */
+#define WPA_CIPHER_GCMP BIT(6)
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
@@ -91,7 +92,8 @@ enum wpa_alg {
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
- WPA_ALG_PMK
+ WPA_ALG_PMK,
+ WPA_ALG_GCMP
};
/**
@@ -102,7 +104,8 @@ enum wpa_cipher {
CIPHER_WEP40,
CIPHER_TKIP,
CIPHER_CCMP,
- CIPHER_WEP104
+ CIPHER_WEP104,
+ CIPHER_GCMP
};
/**
diff --git a/src/common/eapol_common.h b/src/common/eapol_common.h
index 4e392e7c..4811f38a 100644
--- a/src/common/eapol_common.h
+++ b/src/common/eapol_common.h
@@ -38,4 +38,44 @@ enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
+
+#define IEEE8021X_REPLAY_COUNTER_LEN 8
+#define IEEE8021X_KEY_SIGN_LEN 16
+#define IEEE8021X_KEY_IV_LEN 16
+
+#define IEEE8021X_KEY_INDEX_FLAG 0x80
+#define IEEE8021X_KEY_INDEX_MASK 0x03
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_eapol_key {
+ u8 type;
+ /* Note: key_length is unaligned */
+ u8 key_length[2];
+ /* does not repeat within the life of the keying material used to
+ * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
+ u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
+ u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
+ u8 key_index; /* key flag in the most significant bit:
+ * 0 = broadcast (default key),
+ * 1 = unicast (key mapping key); key index is in the
+ * 7 least significant bits */
+ /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
+ * the key */
+ u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
+
+ /* followed by key: if packet body length = 44 + key length, then the
+ * key field (of key_length bytes) contains the key in encrypted form;
+ * if packet body length = 44, key field is absent and key_length
+ * represents the number of least significant octets from
+ * MS-MPPE-Send-Key attribute to be used as the keying material;
+ * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
#endif /* EAPOL_COMMON_H */
diff --git a/src/common/gas.c b/src/common/gas.c
index a67325c3..cff9254b 100644
--- a/src/common/gas.c
+++ b/src/common/gas.c
@@ -1,7 +1,7 @@
/*
* Generic advertisement service (GAS) (IEEE 802.11u)
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,7 +31,7 @@ gas_build_req(u8 action, u8 dialog_token, size_t size)
}
-static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
{
return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
size);
diff --git a/src/common/gas.h b/src/common/gas.h
index 8664a79e..306adc58 100644
--- a/src/common/gas.h
+++ b/src/common/gas.h
@@ -1,7 +1,7 @@
/*
* Generic advertisement service (GAS) (IEEE 802.11u)
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#ifndef GAS_H
#define GAS_H
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
struct wpabuf * gas_build_comeback_req(u8 dialog_token);
struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index d65675cd..d9d3cd05 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -97,6 +97,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->p2p = pos;
elems->p2p_len = elen;
break;
+ case WFD_OUI_TYPE:
+ /* Wi-Fi Alliance - WFD IE */
+ elems->wfd = pos;
+ elems->wfd_len = elen;
+ break;
case HS20_INDICATION_OUI_TYPE:
/* Hotspot 2.0 */
elems->hs20 = pos;
@@ -253,6 +258,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
+ case WLAN_EID_VHT_CAP:
+ elems->vht_capabilities = pos;
+ elems->vht_capabilities_len = elen;
+ break;
+ case WLAN_EID_VHT_OPERATION:
+ elems->vht_operation = pos;
+ elems->vht_operation_len = elen;
+ break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
@@ -397,3 +410,75 @@ const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
return NULL;
}
}
+
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+ const char *name, const char *val)
+{
+ int num, v;
+ const char *pos;
+ struct hostapd_wmm_ac_params *ac;
+
+ /* skip 'wme_ac_' or 'wmm_ac_' prefix */
+ pos = name + 7;
+ if (os_strncmp(pos, "be_", 3) == 0) {
+ num = 0;
+ pos += 3;
+ } else if (os_strncmp(pos, "bk_", 3) == 0) {
+ num = 1;
+ pos += 3;
+ } else if (os_strncmp(pos, "vi_", 3) == 0) {
+ num = 2;
+ pos += 3;
+ } else if (os_strncmp(pos, "vo_", 3) == 0) {
+ num = 3;
+ pos += 3;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
+ return -1;
+ }
+
+ ac = &wmm_ac_params[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ v = atoi(val);
+ if (v < 1 || v > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
+ return -1;
+ }
+ ac->aifs = v;
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
+ return -1;
+ }
+ ac->cwmin = v;
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
+ return -1;
+ }
+ ac->cwmax = v;
+ } else if (os_strcmp(pos, "txop_limit") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 0xffff) {
+ wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
+ return -1;
+ }
+ ac->txop_limit = v;
+ } else if (os_strcmp(pos, "acm") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 1) {
+ wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
+ return -1;
+ }
+ ac->admission_control_mandatory = v;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index d9b2b6c1..bfc3eb27 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -33,8 +33,11 @@ struct ieee802_11_elems {
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
+ const u8 *vht_capabilities;
+ const u8 *vht_operation;
const u8 *vendor_ht_cap;
const u8 *p2p;
+ const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
const u8 *hs20;
@@ -63,8 +66,11 @@ struct ieee802_11_elems {
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
+ u8 vht_capabilities_len;
+ u8 vht_operation_len;
u8 vendor_ht_cap_len;
u8 p2p_len;
+ u8 wfd_len;
u8 interworking_len;
u8 hs20_len;
u8 ext_capab_len;
@@ -81,4 +87,15 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
struct ieee80211_hdr;
const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
+struct hostapd_wmm_ac_params {
+ int cwmin;
+ int cwmax;
+ int aifs;
+ int txop_limit; /* in units of 32us */
+ int admission_control_mandatory;
+};
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+ const char *name, const char *val);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b4f92759..2ab7fbf4 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -701,6 +701,8 @@ struct ieee80211_vht_operation {
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define WFD_IE_VENDOR_TYPE 0x506f9a0a
+#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
#define WMM_OUI_TYPE 2
@@ -923,6 +925,7 @@ enum p2p_service_protocol_type {
P2P_SERV_BONJOUR = 1,
P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3,
+ P2P_SERV_WIFI_DISPLAY = 4,
P2P_SERV_VENDOR_SPECIFIC = 255
};
@@ -934,6 +937,20 @@ enum p2p_sd_status {
};
+enum wifi_display_subelem {
+ WFD_SUBELEM_DEVICE_INFO = 0,
+ WFD_SUBELEM_ASSOCIATED_BSSID = 1,
+ WFD_SUBELEM_AUDIO_FORMATS = 2,
+ WFD_SUBELEM_VIDEO_FORMATS = 3,
+ WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
+ WFD_SUBELEM_CONTENT_PROTECTION = 5,
+ WFD_SUBELEM_COUPLED_SINK = 6,
+ WFD_SUBELEM_EXT_CAPAB = 7,
+ WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
+ WFD_SUBELEM_SESSION_INFO = 9
+};
+
+
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@@ -946,6 +963,8 @@ enum p2p_sd_status {
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
+#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 7a013a80..36febb3a 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -43,8 +43,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
u8 hash[SHA1_MAC_LEN];
switch (ver) {
+#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
return hmac_md5(key, 16, buf, len, mic);
+#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
if (hmac_sha1(key, 16, buf, len, hash))
return -1;
@@ -350,6 +352,8 @@ static int rsn_selector_to_bitfield(const u8 *s)
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
+ return WPA_CIPHER_GCMP;
return 0;
}
@@ -906,6 +910,8 @@ const char * wpa_cipher_txt(int cipher)
return "CCMP";
case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
return "CCMP+TKIP";
+ case WPA_CIPHER_GCMP:
+ return "GCMP";
default:
return "UNKNOWN";
}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 6b50997c..c871ae1b 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -64,6 +64,7 @@
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#endif /* CONFIG_IEEE80211W */
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
@@ -83,6 +84,9 @@
#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#endif /* CONFIG_IEEE80211W */
+#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index b2b06832..58cbe6a0 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -12,7 +12,12 @@
#ifdef CONFIG_CTRL_IFACE_UNIX
#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#ifdef ANDROID
#include <dirent.h>
@@ -44,6 +49,8 @@ struct wpa_ctrl {
struct sockaddr_in local;
struct sockaddr_in dest;
char *cookie;
+ char *remote_ifname;
+ char *remote_ip;
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_CTRL_IFACE_UNIX
int s;
@@ -73,6 +80,7 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
int ret;
size_t res;
int tries = 0;
+ int flags;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
@@ -156,6 +164,19 @@ try_again:
return NULL;
}
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(ctrl->s, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
+ perror("fcntl(ctrl->s, O_NONBLOCK)");
+ /* Not fatal, continue on.*/
+ }
+ }
+
return ctrl;
}
@@ -230,6 +251,9 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
struct wpa_ctrl *ctrl;
char buf[128];
size_t len;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ struct hostent *h;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
@@ -244,7 +268,11 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
}
ctrl->local.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ ctrl->local.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
@@ -255,10 +283,48 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ if (ctrl_path) {
+ char *port, *name;
+ int port_id;
+
+ name = os_strdup(ctrl_path);
+ if (name == NULL) {
+ close(ctrl->s);
+ os_free(ctrl);
+ return NULL;
+ }
+ port = os_strchr(name, ':');
+
+ if (port) {
+ port_id = atoi(&port[1]);
+ port[0] = '\0';
+ } else
+ port_id = WPA_CTRL_IFACE_PORT;
+
+ h = gethostbyname(name);
+ ctrl->remote_ip = os_strdup(name);
+ os_free(name);
+ if (h == NULL) {
+ perror("gethostbyname");
+ close(ctrl->s);
+ os_free(ctrl->remote_ip);
+ os_free(ctrl);
+ return NULL;
+ }
+ ctrl->dest.sin_port = htons(port_id);
+ os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
+ h->h_length);
+ } else
+ ctrl->remote_ip = os_strdup("localhost");
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
perror("connect");
close(ctrl->s);
+ os_free(ctrl->remote_ip);
os_free(ctrl);
return NULL;
}
@@ -269,14 +335,31 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
ctrl->cookie = os_strdup(buf);
}
+ if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
+ buf[len] = '\0';
+ ctrl->remote_ifname = os_strdup(buf);
+ }
+
return ctrl;
}
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
+{
+#define WPA_CTRL_MAX_PS_NAME 100
+ static char ps[WPA_CTRL_MAX_PS_NAME] = {};
+ os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
+ ctrl->remote_ip, ctrl->remote_ifname);
+ return ps;
+}
+
+
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
close(ctrl->s);
os_free(ctrl->cookie);
+ os_free(ctrl->remote_ifname);
+ os_free(ctrl->remote_ip);
os_free(ctrl);
}
@@ -289,6 +372,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
+ struct os_time started_at;
int res;
fd_set rfds;
const char *_cmd;
@@ -315,7 +399,30 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
_cmd_len = cmd_len;
}
+ errno = 0;
+ started_at.sec = 0;
+ started_at.usec = 0;
+retry_send:
if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+ if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
+ {
+ /*
+ * Must be a non-blocking socket... Try for a bit
+ * longer before giving up.
+ */
+ if (started_at.sec == 0)
+ os_get_time(&started_at);
+ else {
+ struct os_time n;
+ os_get_time(&n);
+ /* Try for a few seconds. */
+ if (n.sec > started_at.sec + 5)
+ goto send_err;
+ }
+ os_sleep(1, 0);
+ goto retry_send;
+ }
+ send_err:
os_free(cmd_buf);
return -1;
}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index a440b69e..84f11953 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -48,6 +48,10 @@ extern "C" {
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+/** Network block temporarily disabled (e.g., due to authentication failure) */
+#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
+/** Temporarily disabled network block re-enabled */
+#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
/** wpa_supplicant state change */
@@ -133,6 +137,8 @@ extern "C" {
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
@@ -164,6 +170,7 @@ extern "C" {
#define WPA_BSS_MASK_WPS_SCAN BIT(13)
#define WPA_BSS_MASK_P2P_SCAN BIT(14)
#define WPA_BSS_MASK_INTERNETW BIT(15)
+#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
/* wpa_supplicant/hostapd control interface access */
@@ -290,6 +297,8 @@ int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
+
#ifdef ANDROID
/**
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
@@ -302,8 +311,11 @@ void wpa_ctrl_cleanup(void);
#endif /* ANDROID */
#ifdef CONFIG_CTRL_IFACE_UDP
+/* Port range for multiple wpa_supplicant instances and multiple VIFs */
#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
#endif /* CONFIG_CTRL_IFACE_UDP */
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index b221dd44..18b50548 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -31,16 +31,17 @@ LIB_OBJS= \
md4-internal.o \
md5.o \
md5-internal.o \
- md5-non-fips.o \
milenage.o \
ms_funcs.o \
rc4.o \
sha1.o \
sha1-internal.o \
sha1-pbkdf2.o \
+ sha1-prf.o \
sha1-tlsprf.o \
sha1-tprf.o \
sha256.o \
+ sha256-prf.o \
sha256-tlsprf.o \
sha256-internal.o
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 7e61cb97..26b9acf2 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -41,21 +41,6 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
*/
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
-#ifdef CONFIG_FIPS
-/**
- * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed)
- * @num_elem: Number of elements in the data vector
- * @addr: Pointers to the data areas
- * @len: Lengths of the data blocks
- * @mac: Buffer for the hash
- * Returns: 0 on success, -1 on failure
- */
-int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac);
-#else /* CONFIG_FIPS */
-#define md5_vector_non_fips_allow md5_vector
-#endif /* CONFIG_FIPS */
-
/**
* sha1_vector - SHA-1 hash for data vector
@@ -461,4 +446,15 @@ int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len);
+/**
+ * crypto_get_random - Generate cryptographically strong pseudy-random bytes
+ * @buf: Buffer for data
+ * @len: Number of bytes to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * If the PRNG does not have enough entropy to ensure unpredictable byte
+ * sequence, this functions must return -1.
+ */
+int crypto_get_random(void *buf, size_t len);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 8506fff4..711e312d 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -15,6 +15,10 @@
#include <openssl/evp.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#ifdef CONFIG_OPENSSL_CMAC
+#include <openssl/cmac.h>
+#endif /* CONFIG_OPENSSL_CMAC */
#include "common.h"
#include "wpabuf.h"
@@ -69,21 +73,14 @@ static BIGNUM * get_group5_prime(void)
#define NO_SHA256_WRAPPER
#endif
-static int openssl_digest_vector(const EVP_MD *type, int non_fips,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
+static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
EVP_MD_CTX ctx;
size_t i;
unsigned int mac_len;
EVP_MD_CTX_init(&ctx);
-#ifdef CONFIG_FIPS
-#ifdef OPENSSL_FIPS
- if (non_fips)
- EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif /* OPENSSL_FIPS */
-#endif /* CONFIG_FIPS */
if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -109,7 +106,7 @@ static int openssl_digest_vector(const EVP_MD *type, int non_fips,
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
+ return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
}
@@ -173,22 +170,13 @@ out:
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
+ return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
}
-#ifdef CONFIG_FIPS
-int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
-{
- return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
-}
-#endif /* CONFIG_FIPS */
-
-
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
+ return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
}
@@ -196,60 +184,124 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
- return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
- mac);
+ return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
}
#endif /* NO_SHA256_WRAPPER */
+static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
+{
+ switch (keylen) {
+ case 16:
+ return EVP_aes_128_ecb();
+ case 24:
+ return EVP_aes_192_ecb();
+ case 32:
+ return EVP_aes_256_ecb();
+ }
+
+ return NULL;
+}
+
+
void * aes_encrypt_init(const u8 *key, size_t len)
{
- AES_KEY *ak;
- ak = os_malloc(sizeof(*ak));
- if (ak == NULL)
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+
+ type = aes_get_evp_cipher(len);
+ if (type == NULL)
+ return NULL;
+
+ ctx = os_malloc(sizeof(*ctx));
+ if (ctx == NULL)
return NULL;
- if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
- os_free(ak);
+ EVP_CIPHER_CTX_init(ctx);
+ if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+ os_free(ctx);
return NULL;
}
- return ak;
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ return ctx;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
- AES_encrypt(plain, crypt, ctx);
+ EVP_CIPHER_CTX *c = ctx;
+ int clen = 16;
+ if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
}
void aes_encrypt_deinit(void *ctx)
{
- os_free(ctx);
+ EVP_CIPHER_CTX *c = ctx;
+ u8 buf[16];
+ int len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(c, buf, &len) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: "
+ "%s", ERR_error_string(ERR_get_error(), NULL));
+ }
+ if (len != 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+ "in AES encrypt", len);
+ }
+ EVP_CIPHER_CTX_cleanup(c);
+ os_free(c);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
- AES_KEY *ak;
- ak = os_malloc(sizeof(*ak));
- if (ak == NULL)
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+
+ type = aes_get_evp_cipher(len);
+ if (type == NULL)
return NULL;
- if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
- os_free(ak);
+
+ ctx = os_malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+ EVP_CIPHER_CTX_init(ctx);
+ if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+ os_free(ctx);
return NULL;
}
- return ak;
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ return ctx;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
- AES_decrypt(crypt, plain, ctx);
+ EVP_CIPHER_CTX *c = ctx;
+ int plen = 16;
+ if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
}
void aes_decrypt_deinit(void *ctx)
{
+ EVP_CIPHER_CTX *c = ctx;
+ u8 buf[16];
+ int len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(c, buf, &len) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: "
+ "%s", ERR_error_string(ERR_get_error(), NULL));
+ }
+ if (len != 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+ "in AES decrypt", len);
+ }
+ EVP_CIPHER_CTX_cleanup(c);
os_free(ctx);
}
@@ -571,6 +623,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
+ HMAC_CTX_init(&ctx->ctx);
#if OPENSSL_VERSION_NUMBER < 0x00909000
HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
@@ -623,3 +676,145 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
return -1;
}
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
+ (unsigned char *) ssid,
+ ssid_len, 4096, buflen, buf) != 1)
+ return -1;
+#else /* openssl < 0.9.8 */
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+ ssid_len, 4096, buflen, buf) != 1)
+ return -1;
+#endif /* openssl < 0.9.8 */
+ return 0;
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HMAC_CTX ctx;
+ size_t i;
+ unsigned int mdlen;
+ int res;
+
+ HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
+#else /* openssl < 0.9.9 */
+ if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+ return -1;
+#endif /* openssl < 0.9.9 */
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(&ctx, addr[i], len[i]);
+
+ mdlen = 20;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Final(&ctx, mac, &mdlen);
+ res = 1;
+#else /* openssl < 0.9.9 */
+ res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+ HMAC_CTX_cleanup(&ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HMAC_CTX ctx;
+ size_t i;
+ unsigned int mdlen;
+ int res;
+
+ HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
+#else /* openssl < 0.9.9 */
+ if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
+ return -1;
+#endif /* openssl < 0.9.9 */
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(&ctx, addr[i], len[i]);
+
+ mdlen = 32;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Final(&ctx, mac, &mdlen);
+ res = 1;
+#else /* openssl < 0.9.9 */
+ res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+ HMAC_CTX_cleanup(&ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+int crypto_get_random(void *buf, size_t len)
+{
+ if (RAND_bytes(buf, len) != 1)
+ return -1;
+ return 0;
+}
+
+
+#ifdef CONFIG_OPENSSL_CMAC
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ CMAC_CTX *ctx;
+ int ret = -1;
+ size_t outlen, i;
+
+ ctx = CMAC_CTX_new();
+ if (ctx == NULL)
+ return -1;
+
+ if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ goto fail;
+ for (i = 0; i < num_elem; i++) {
+ if (!CMAC_Update(ctx, addr[i], len[i]))
+ goto fail;
+ }
+ if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16)
+ goto fail;
+
+ ret = 0;
+fail:
+ CMAC_CTX_free(ctx);
+ return ret;
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+#endif /* CONFIG_OPENSSL_CMAC */
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index 92f0b572..d69eceab 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -31,13 +31,14 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
u8 *xpos = x;
u32 carry;
- if (seed_len > sizeof(xkey))
+ if (seed_len < sizeof(xkey))
+ os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+ else
seed_len = sizeof(xkey);
/* FIPS 186-2 + change notice 1 */
os_memcpy(xkey, seed, seed_len);
- os_memset(xkey + seed_len, 0, 64 - seed_len);
t[0] = 0x67452301;
t[1] = 0xEFCDAB89;
t[2] = 0x98BADCFE;
diff --git a/src/crypto/md5-non-fips.c b/src/crypto/md5-non-fips.c
deleted file mode 100644
index 418f7828..00000000
--- a/src/crypto/md5-non-fips.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * MD5 hash implementation and interface functions (non-FIPS allowed cases)
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "md5.h"
-#include "crypto.h"
-
-
-/**
- * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @num_elem: Number of elements in the data vector
- * @addr: Pointers to the data areas
- * @len: Lengths of the data blocks
- * @mac: Buffer for the hash (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
-{
- u8 k_pad[64]; /* padding - key XORd with ipad/opad */
- u8 tk[16];
- const u8 *_addr[6];
- size_t i, _len[6];
-
- if (num_elem > 5) {
- /*
- * Fixed limit on the number of fragments to avoid having to
- * allocate memory (which could fail).
- */
- return -1;
- }
-
- /* if key is longer than 64 bytes reset it to key = MD5(key) */
- if (key_len > 64) {
- if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
- return -1;
- key = tk;
- key_len = 16;
- }
-
- /* the HMAC_MD5 transform looks like:
- *
- * MD5(K XOR opad, MD5(K XOR ipad, text))
- *
- * where K is an n byte key
- * ipad is the byte 0x36 repeated 64 times
- * opad is the byte 0x5c repeated 64 times
- * and text is the data being protected */
-
- /* start out by storing key in ipad */
- os_memset(k_pad, 0, sizeof(k_pad));
- os_memcpy(k_pad, key, key_len);
-
- /* XOR key with ipad values */
- for (i = 0; i < 64; i++)
- k_pad[i] ^= 0x36;
-
- /* perform inner MD5 */
- _addr[0] = k_pad;
- _len[0] = 64;
- for (i = 0; i < num_elem; i++) {
- _addr[i + 1] = addr[i];
- _len[i + 1] = len[i];
- }
- if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
- return -1;
-
- os_memset(k_pad, 0, sizeof(k_pad));
- os_memcpy(k_pad, key, key_len);
- /* XOR key with opad values */
- for (i = 0; i < 64; i++)
- k_pad[i] ^= 0x5c;
-
- /* perform outer MD5 */
- _addr[0] = k_pad;
- _len[0] = 64;
- _addr[1] = mac;
- _len[1] = MD5_MAC_LEN;
- return md5_vector_non_fips_allow(2, _addr, _len, mac);
-}
-
-
-/**
- * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @data: Pointers to the data area
- * @data_len: Length of the data area
- * @mac: Buffer for the hash (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac)
-{
- return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
- &data_len, mac);
-}
diff --git a/src/crypto/md5.h b/src/crypto/md5.h
index 4d6e9045..33f8426c 100644
--- a/src/crypto/md5.h
+++ b/src/crypto/md5.h
@@ -15,15 +15,5 @@ int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac);
-#ifdef CONFIG_FIPS
-int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac);
-int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac);
-#else /* CONFIG_FIPS */
-#define hmac_md5_vector_non_fips_allow hmac_md5_vector
-#define hmac_md5_non_fips_allow hmac_md5
-#endif /* CONFIG_FIPS */
#endif /* MD5_H */
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index 3594d846..b2bbab2b 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -173,8 +173,9 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
u8 challenge[8];
u8 password_hash[16];
- challenge_hash(peer_challenge, auth_challenge, username, username_len,
- challenge);
+ if (challenge_hash(peer_challenge, auth_challenge, username,
+ username_len, challenge))
+ return -1;
if (nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
@@ -260,8 +261,9 @@ int generate_authenticator_response_pwhash(
if (sha1_vector(3, addr1, len1, response))
return -1;
- challenge_hash(peer_challenge, auth_challenge, username, username_len,
- challenge);
+ if (challenge_hash(peer_challenge, auth_challenge, username,
+ username_len, challenge))
+ return -1;
return sha1_vector(3, addr2, len2, response);
}
diff --git a/src/crypto/random.c b/src/crypto/random.c
index d85c3e66..053740e9 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -29,6 +29,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "crypto/crypto.h"
#include "sha1.h"
#include "random.h"
@@ -177,6 +178,27 @@ int random_get_bytes(void *buf, size_t len)
*bytes++ ^= tmp[i];
left -= siz;
}
+
+#ifdef CONFIG_FIPS
+ /* Mix in additional entropy from the crypto module */
+ left = len;
+ while (left) {
+ size_t siz, i;
+ u8 tmp[EXTRACT_LEN];
+ if (crypto_get_random(tmp, sizeof(tmp)) < 0) {
+ wpa_printf(MSG_ERROR, "random: No entropy available "
+ "for generating strong random bytes");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module",
+ tmp, sizeof(tmp));
+ siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+ for (i = 0; i < siz; i++)
+ *bytes++ ^= tmp[i];
+ left -= siz;
+ }
+#endif /* CONFIG_FIPS */
+
wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
if (entropy < len)
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 450c2a03..8effe2fe 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -11,7 +11,7 @@
#include "common.h"
#include "sha1.h"
-static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
+static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid,
size_t ssid_len, int iterations, unsigned int count,
u8 *digest)
{
@@ -22,7 +22,7 @@ static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
size_t len[2];
size_t passphrase_len = os_strlen(passphrase);
- addr[0] = (u8 *) ssid;
+ addr[0] = ssid;
len[0] = ssid_len;
addr[1] = count_buf;
len[1] = 4;
@@ -69,7 +69,7 @@ static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
* iterations is set to 4096 and buflen to 32. This function is described in
* IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
*/
-int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
unsigned int count = 0;
diff --git a/src/crypto/sha1-prf.c b/src/crypto/sha1-prf.c
new file mode 100644
index 00000000..90b9e74b
--- /dev/null
+++ b/src/crypto/sha1-prf.c
@@ -0,0 +1,66 @@
+/*
+ * SHA1-based PRF
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., PMK in IEEE 802.11i).
+ */
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ u8 counter = 0;
+ size_t pos, plen;
+ u8 hash[SHA1_MAC_LEN];
+ size_t label_len = os_strlen(label) + 1;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = (u8 *) label;
+ len[0] = label_len;
+ addr[1] = data;
+ len[1] = data_len;
+ addr[2] = &counter;
+ len[2] = 1;
+
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ if (plen >= SHA1_MAC_LEN) {
+ if (hmac_sha1_vector(key, key_len, 3, addr, len,
+ &buf[pos]))
+ return -1;
+ pos += SHA1_MAC_LEN;
+ } else {
+ if (hmac_sha1_vector(key, key_len, 3, addr, len,
+ hash))
+ return -1;
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index e79265ba..0effd9b7 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -71,19 +71,16 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
S2--;
}
- hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
- A_MD5);
+ hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
MD5_pos = MD5_MAC_LEN;
SHA1_pos = SHA1_MAC_LEN;
for (i = 0; i < outlen; i++) {
if (MD5_pos == MD5_MAC_LEN) {
- hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr,
- MD5_len, P_MD5);
+ hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
MD5_pos = 0;
- hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN,
- A_MD5);
+ hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
}
if (SHA1_pos == SHA1_MAC_LEN) {
hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index 274d81fa..d48c77d7 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -102,56 +102,3 @@ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
{
return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
}
-
-
-/**
- * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
- * @key: Key for PRF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @data: Extra data to bind into the key
- * @data_len: Length of the data
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- * Returns: 0 on success, -1 of failure
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key (e.g., PMK in IEEE 802.11i).
- */
-int sha1_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
-{
- u8 counter = 0;
- size_t pos, plen;
- u8 hash[SHA1_MAC_LEN];
- size_t label_len = os_strlen(label) + 1;
- const unsigned char *addr[3];
- size_t len[3];
-
- addr[0] = (u8 *) label;
- len[0] = label_len;
- addr[1] = data;
- len[1] = data_len;
- addr[2] = &counter;
- len[2] = 1;
-
- pos = 0;
- while (pos < buf_len) {
- plen = buf_len - pos;
- if (plen >= SHA1_MAC_LEN) {
- if (hmac_sha1_vector(key, key_len, 3, addr, len,
- &buf[pos]))
- return -1;
- pos += SHA1_MAC_LEN;
- } else {
- if (hmac_sha1_vector(key, key_len, 3, addr, len,
- hash))
- return -1;
- os_memcpy(&buf[pos], hash, plen);
- break;
- }
- counter++;
- }
-
- return 0;
-}
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index 08e5a59d..933cd81b 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -22,6 +22,6 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed,
size_t seed_len, u8 *out, size_t outlen);
-int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen);
#endif /* SHA1_H */
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
new file mode 100644
index 00000000..0da6d130
--- /dev/null
+++ b/src/crypto/sha256-prf.c
@@ -0,0 +1,64 @@
+/*
+ * SHA256-based PRF (IEEE 802.11r)
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ u16 counter = 1;
+ size_t pos, plen;
+ u8 hash[SHA256_MAC_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 counter_le[2], length_le[2];
+
+ addr[0] = counter_le;
+ len[0] = 2;
+ addr[1] = (u8 *) label;
+ len[1] = os_strlen(label);
+ addr[2] = data;
+ len[2] = data_len;
+ addr[3] = length_le;
+ len[3] = sizeof(length_le);
+
+ WPA_PUT_LE16(length_le, buf_len * 8);
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ WPA_PUT_LE16(counter_le, counter);
+ if (plen >= SHA256_MAC_LEN) {
+ hmac_sha256_vector(key, key_len, 4, addr, len,
+ &buf[pos]);
+ pos += SHA256_MAC_LEN;
+ } else {
+ hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+}
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index 5c09ed19..b55e976f 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -1,6 +1,6 @@
/*
* SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,9 +21,10 @@
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[32];
@@ -35,12 +36,13 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
- return;
+ return -1;
}
/* if key is longer than 64 bytes reset it to key = SHA256(key) */
if (key_len > 64) {
- sha256_vector(1, &key, &key_len, tk);
+ if (sha256_vector(1, &key, &key_len, tk) < 0)
+ return -1;
key = tk;
key_len = 32;
}
@@ -68,7 +70,8 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
- sha256_vector(1 + num_elem, _addr, _len, mac);
+ if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
@@ -81,7 +84,7 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
_len[0] = 64;
_addr[1] = mac;
_len[1] = SHA256_MAC_LEN;
- sha256_vector(2, _addr, _len, mac);
+ return sha256_vector(2, _addr, _len, mac);
}
@@ -91,61 +94,11 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
- * @mac: Buffer for the hash (20 bytes)
- */
-void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac)
-{
- hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
-}
-
-
-/**
- * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
- * @key: Key for PRF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @data: Extra data to bind into the key
- * @data_len: Length of the data
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key.
+ * @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
{
- u16 counter = 1;
- size_t pos, plen;
- u8 hash[SHA256_MAC_LEN];
- const u8 *addr[4];
- size_t len[4];
- u8 counter_le[2], length_le[2];
-
- addr[0] = counter_le;
- len[0] = 2;
- addr[1] = (u8 *) label;
- len[1] = os_strlen(label);
- addr[2] = data;
- len[2] = data_len;
- addr[3] = length_le;
- len[3] = sizeof(length_le);
-
- WPA_PUT_LE16(length_le, buf_len * 8);
- pos = 0;
- while (pos < buf_len) {
- plen = buf_len - pos;
- WPA_PUT_LE16(counter_le, counter);
- if (plen >= SHA256_MAC_LEN) {
- hmac_sha256_vector(key, key_len, 4, addr, len,
- &buf[pos]);
- pos += SHA256_MAC_LEN;
- } else {
- hmac_sha256_vector(key, key_len, 4, addr, len, hash);
- os_memcpy(&buf[pos], hash, plen);
- break;
- }
- counter++;
- }
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 412fb603..fcac8004 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -11,10 +11,10 @@
#define SHA256_MAC_LEN 32
-void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac);
-void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac);
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 990f6e6e..b61e4393 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -81,6 +81,7 @@ struct tls_config {
#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
+#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
/**
* struct tls_connection_params - Parameters for TLS connection
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index f2b541e0..dfb63ad7 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -711,6 +711,8 @@ void * tls_init(const struct tls_config *conf)
"mode");
ERR_load_crypto_strings();
ERR_print_errors_fp(stderr);
+ os_free(tls_global);
+ tls_global = NULL;
return NULL;
} else
wpa_printf(MSG_INFO, "Running in FIPS mode");
@@ -719,6 +721,8 @@ void * tls_init(const struct tls_config *conf)
if (conf && conf->fips_mode) {
wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
"supported");
+ os_free(tls_global);
+ tls_global = NULL;
return NULL;
}
#endif /* OPENSSL_FIPS */
@@ -1936,6 +1940,8 @@ static int tls_connection_engine_ca_cert(void *_ssl_ctx,
wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
"to certificate store", __func__);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ conn->ca_cert_verify = 1;
+
return 0;
#else /* OPENSSL_NO_ENGINE */
@@ -2099,7 +2105,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
os_free(passwd);
-
+
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
"verification");
@@ -2145,7 +2151,7 @@ static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
os_free(passwd);
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-
+
if (!SSL_CTX_check_private_key(ssl_ctx)) {
tls_show_errors(MSG_INFO, __func__,
"Private key failed verification");
@@ -2307,6 +2313,11 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
+#ifdef CONFIG_FIPS
+ wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+ "mode");
+ return -1;
+#else /* CONFIG_FIPS */
SSL *ssl;
if (conn == NULL || keys == NULL)
@@ -2324,6 +2335,7 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
keys->server_random_len = SSL3_RANDOM_SIZE;
return 0;
+#endif /* CONFIG_FIPS */
}
@@ -2331,6 +2343,19 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL *ssl;
+ if (conn == NULL)
+ return -1;
+ if (server_random_first)
+ return -1;
+ ssl = conn->ssl;
+ if (SSL_export_keying_material(ssl, out, out_len, label,
+ os_strlen(label), NULL, 0, 0) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
+ return 0;
+ }
+#endif
return -1;
}
@@ -2763,6 +2788,13 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
+#ifdef SSL_OP_NO_TICKET
+ if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+ SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+ else
+ SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_OP_NO_TICKET */
+
conn->flags = params->flags;
tls_get_errors(tls_ctx);
@@ -2798,6 +2830,13 @@ int tls_global_set_params(void *tls_ctx,
return -1;
}
+#ifdef SSL_OP_NO_TICKET
+ if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+ else
+ SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_OP_NO_TICKET */
+
return 0;
}
@@ -2807,6 +2846,7 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
{
const EVP_CIPHER *c;
const EVP_MD *h;
+ int md_size;
if (conn == NULL || conn->ssl == NULL ||
conn->ssl->enc_read_ctx == NULL ||
@@ -2820,9 +2860,20 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
#else
h = conn->ssl->read_hash;
#endif
+ if (h)
+ md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ else if (conn->ssl->s3)
+ md_size = conn->ssl->s3->tmp.new_mac_secret_size;
+#endif
+ else
+ return -1;
+ wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+ "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+ EVP_CIPHER_iv_length(c));
return 2 * (EVP_CIPHER_key_length(c) +
- EVP_MD_size(h) +
+ md_size +
EVP_CIPHER_iv_length(c));
}
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
index 6df71602..5906527a 100644
--- a/src/drivers/android_drv.h
+++ b/src/drivers/android_drv.h
@@ -14,8 +14,6 @@
#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
-#define WEXT_CSCAN_AMOUNT 9
-
#define MAX_SSID_LEN 32
#define MAX_DRV_CMD_SIZE 248
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0aab61ec..e3920722 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -274,6 +274,15 @@ struct wpa_driver_scan_params {
size_t num_filter_ssids;
/**
+ * filter_rssi - Filter by RSSI
+ *
+ * The driver may filter scan results in firmware to reduce host
+ * wakeups and thereby save power. Specify the RSSI threshold in s32
+ * dBm.
+ */
+ s32 filter_rssi;
+
+ /**
* p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
*
* When set, the driver is expected to remove rates 1, 2, 5.5, and 11
@@ -731,6 +740,11 @@ struct wpa_driver_ap_params {
* This is used by driver which advertises this capability.
*/
int ap_max_inactivity;
+
+ /**
+ * disable_dgaf - Whether group-addressed frames are disabled
+ */
+ int disable_dgaf;
};
/**
@@ -751,6 +765,7 @@ struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_ENC_TKIP 0x00000004
#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008
#define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010
+#define WPA_DRIVER_CAPA_ENC_GCMP 0x00000020
unsigned int enc;
#define WPA_DRIVER_AUTH_OPEN 0x00000001
@@ -817,6 +832,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
/* Driver supports inactivity timer in AP mode */
#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
+/* Driver expects user space implementation of MLME in AP mode */
+#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000
unsigned int flags;
int max_scan_ssids;
@@ -983,6 +1000,23 @@ enum tdls_oper {
TDLS_DISABLE
};
+enum wnm_oper {
+ WNM_SLEEP_ENTER_CONFIRM,
+ WNM_SLEEP_ENTER_FAIL,
+ WNM_SLEEP_EXIT_CONFIRM,
+ WNM_SLEEP_EXIT_FAIL,
+ WNM_SLEEP_TFS_REQ_IE_ADD, /* STA requests driver to add TFS req IE */
+ WNM_SLEEP_TFS_REQ_IE_NONE, /* STA requests empty TFS req IE */
+ WNM_SLEEP_TFS_REQ_IE_SET, /* AP requests driver to set TFS req IE for
+ * a STA */
+ WNM_SLEEP_TFS_RESP_IE_ADD, /* AP requests driver to add TFS resp IE
+ * for a STA */
+ WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */
+ WNM_SLEEP_TFS_RESP_IE_SET, /* AP requests driver to set TFS resp IE
+ * for a STA */
+ WNM_SLEEP_TFS_IE_DEL /* AP delete the TFS IE */
+};
+
/**
* struct wpa_signal_info - Information about channel signal quality
*/
@@ -1042,7 +1076,8 @@ struct wpa_driver_ops {
* @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
+ * %WPA_ALG_GCMP);
* %WPA_ALG_NONE clears the key.
* @addr: Address of the peer STA (BSSID of the current AP when setting
* pairwise key in station mode), ff:ff:ff:ff:ff:ff for
@@ -1059,11 +1094,11 @@ struct wpa_driver_ops {
* for Rx keys (in most cases, this is only used with broadcast
* keys and set to zero for unicast keys); %NULL if not set
* @seq_len: length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
+ * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
* @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
* 8-byte Rx Mic Key
* @key_len: length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP: 16, IGTK: 16)
+ * TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
*
* Returns: 0 on success, -1 on failure
*
@@ -1568,9 +1603,9 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*
* This function is used to fetch the last used TSC/packet number for
- * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so
- * there is no strict requirement on implementing support for unicast
- * keys (i.e., addr != %NULL).
+ * a TKIP, CCMP, GCMP, or BIP/IGTK key. It is mainly used with group
+ * keys, so there is no strict requirement on implementing support for
+ * unicast keys (i.e., addr != %NULL).
*/
int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
int idx, u8 *seq);
@@ -2399,6 +2434,18 @@ struct wpa_driver_ops {
int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
/**
+ * wnm_oper - Notify driver of the WNM frame reception
+ * @priv: Private driver interface data
+ * @oper: WNM operation. See %enum wnm_oper
+ * @peer: Destination (peer) MAC address
+ * @buf: Buffer for the driver to fill in (for getting IE)
+ * @buf_len: Return the len of buf
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*wnm_oper)(void *priv, enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len);
+
+ /**
* signal_poll - Get current connection information
* @priv: Private driver interface data
* @signal_info: Connection info structure
@@ -3006,7 +3053,14 @@ enum wpa_event_type {
*
* Described in wpa_event_data.ch_switch
* */
- EVENT_CH_SWITCH
+ EVENT_CH_SWITCH,
+
+ /**
+ * EVENT_WNM - Request WNM operation
+ *
+ * This event can be used to request a WNM operation to be performed.
+ */
+ EVENT_WNM
};
@@ -3209,6 +3263,24 @@ union wpa_event_data {
} tdls;
/**
+ * struct wnm - Data for EVENT_WNM
+ */
+ struct wnm {
+ u8 addr[ETH_ALEN];
+ enum {
+ WNM_OPER_SLEEP,
+ } oper;
+ enum {
+ WNM_SLEEP_ENTER,
+ WNM_SLEEP_EXIT
+ } sleep_action;
+ int sleep_intval;
+ u16 reason_code;
+ u8 *buf;
+ u16 buf_len;
+ } wnm;
+
+ /**
* struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
*
* During FT (IEEE 802.11r) authentication sequence, the driver is
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 73898d3f..fefae8c3 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -14,6 +14,12 @@
#include <sys/ioctl.h>
#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "l2_packet/l2_packet.h"
+#include "p2p/p2p.h"
+
+#include "common.h"
#ifndef _BYTE_ORDER
#ifdef WORDS_BIGENDIAN
#define _BYTE_ORDER _BIG_ENDIAN
@@ -837,7 +843,88 @@ static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
}
#endif /* CONFIG_IEEE80211R */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+#ifdef CONFIG_HS20
+static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct atheros_driver_data *drv = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ union wpa_event_data event;
+
+ /* Send the Action frame for HS20 processing */
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
+ sizeof(mgmt->u.action.u.public_action))
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
+ mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+ return;
+
+ wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = (const u8 *) mgmt;
+ event.rx_mgmt.frame_len = len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+}
+#endif /* CONFIG_HS20 */
+
+#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct atheros_driver_data *drv = ctx;
+ union wpa_event_data event;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ u16 stype;
+
+ /* Do 11R processing for WNM ACTION frames */
+ if (len < IEEE80211_HDRLEN)
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+ return;
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+ (int) len);
+
+ if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+ __func__);
+ return;
+ }
+
+ switch (stype) {
+ case WLAN_FC_STYPE_ACTION:
+ if (&mgmt->u.action.category > buf + len)
+ break;
+ os_memset(&event, 0, sizeof(event));
+ event.rx_action.da = mgmt->da;
+ event.rx_action.sa = mgmt->sa;
+ event.rx_action.bssid = mgmt->bssid;
+ event.rx_action.category = mgmt->u.action.category;
+ event.rx_action.data = &mgmt->u.action.category;
+ event.rx_action.len = buf + len - event.rx_action.data;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+ break;
+ default:
+ break;
+ }
+}
+#endif /* CONFIG_IEEE80211V */
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211V)
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -847,6 +934,12 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
#ifdef CONFIG_IEEE80211R
atheros_raw_recv_11r(ctx, src_addr, buf, len);
#endif /* CONFIG_IEEE80211R */
+#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+ atheros_raw_recv_11v(ctx, src_addr, buf, len);
+#endif /* CONFIG_IEEE80211V */
+#ifdef CONFIG_HS20
+ atheros_raw_recv_hs20(ctx, src_addr, buf, len);
+#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
@@ -862,8 +955,15 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
#endif /* CONFIG_WPS */
#ifdef CONFIG_IEEE80211R
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
- IEEE80211_FILTER_TYPE_AUTH);
+ IEEE80211_FILTER_TYPE_AUTH |
+ IEEE80211_FILTER_TYPE_ACTION);
#endif
+#ifdef CONFIG_IEEE80211V
+ filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_IEEE80211V */
+#ifdef CONFIG_HS20
+ filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_HS20 */
if (filt.app_filterype) {
ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
sizeof(struct ieee80211req_set_filter));
@@ -1165,8 +1265,8 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
*/
wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
#endif /* CONFIG_WPS */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
-#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
/*
* Atheros driver uses a hack to pass Probe Request frames as a
@@ -1175,50 +1275,136 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
* Format: "Manage.prob_req <frame len>" | zero padding | frame
*/
int len = atoi(custom + 16);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
"length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
} else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
int len = atoi(custom + 17);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
"assoc_req/auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
} else if (strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
int len = atoi(custom + 14);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
"assoc_req/auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
} else if (strncmp(custom, "Manage.auth ", 12) == 0) {
/* Format: "Manage.auth <frame len>" | zero padding | frame
*/
int len = atoi(custom + 12);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
"assoc_req/auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
}
}
+/*
+* Handle size of data problem. WEXT only allows data of 256 bytes for custom
+* events, and p2p data can be much bigger. So the athr driver sends a small
+* event telling me to collect the big data with an ioctl.
+* On the first event, send all pending events to supplicant.
+*/
+static void fetch_pending_big_events(struct atheros_driver_data *drv)
+{
+ union wpa_event_data event;
+ const struct ieee80211_mgmt *mgmt;
+ u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */
+ u16 fc, stype;
+ struct iwreq iwr;
+ size_t data_len;
+ u32 freq, frame_type;
+
+ while (1) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.data.pointer = (void *) tbuf;
+ iwr.u.data.length = sizeof(tbuf);
+ iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME;
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr)
+ < 0) {
+ if (errno == ENOSPC) {
+ wpa_printf(MSG_DEBUG, "%s:%d exit",
+ __func__, __LINE__);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM["
+ "P2P_FETCH_FRAME] failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+ data_len = iwr.u.data.length;
+ wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data",
+ (u8 *) tbuf, data_len);
+ if (data_len < sizeof(freq) + sizeof(frame_type) + 24) {
+ wpa_printf(MSG_DEBUG, "athr: frame too short");
+ continue;
+ }
+ os_memcpy(&freq, tbuf, sizeof(freq));
+ os_memcpy(&frame_type, &tbuf[sizeof(freq)],
+ sizeof(frame_type));
+ mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)];
+ data_len -= sizeof(freq) + sizeof(frame_type);
+
+ if (frame_type == IEEE80211_EV_RX_MGMT) {
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u "
+ "freq=%u len=%u", stype, freq, (int) data_len);
+
+ if (stype == WLAN_FC_STYPE_ACTION) {
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = (const u8 *) mgmt;
+ event.rx_mgmt.frame_len = data_len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT,
+ &event);
+ continue;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
+ __func__, frame_type);
+ continue;
+ }
+ }
+}
+
+static void
+atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
+ int opcode, char *buf, int len)
+{
+ switch (opcode) {
+ case IEEE80211_EV_RX_MGMT:
+ wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
+ fetch_pending_big_events(drv);
+ break;
+ default:
+ break;
+ }
+}
+
static void
atheros_wireless_event_wireless(struct atheros_driver_data *drv,
char *data, int len)
@@ -1274,8 +1460,15 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv,
return; /* XXX */
memcpy(buf, custom, iwe->u.data.length);
buf[iwe->u.data.length] = '\0';
- atheros_wireless_event_wireless_custom(
- drv, buf, buf + iwe->u.data.length);
+
+ if (iwe->u.data.flags != 0) {
+ atheros_wireless_event_atheros_custom(
+ drv, (int) iwe->u.data.flags,
+ buf, len);
+ } else {
+ atheros_wireless_event_wireless_custom(
+ drv, buf, buf + iwe->u.data.length);
+ }
free(buf);
break;
}
@@ -1709,6 +1902,221 @@ static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
#endif /* CONFIG_IEEE80211R */
+/* Use only to set a big param, get will not work. */
+static int
+set80211big(struct atheros_driver_data *drv, int op, const void *data, int len)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.data.pointer = (void *) data;
+ iwr.u.data.length = len;
+ iwr.u.data.flags = op;
+ wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x",
+ __func__, op, op, athr_get_param_name(op), len);
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d "
+ "value=0x%x,0x%x failed: %d (%s)",
+ __func__, op, athr_get_ioctl_name(op), iwr.u.mode,
+ iwr.u.mode, iwr.u.data.length,
+ iwr.u.data.flags, errno, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+
+static int atheros_send_action(void *priv, unsigned int freq,
+ unsigned int wait,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len, int no_cck)
+{
+ struct atheros_driver_data *drv = priv;
+ struct ieee80211_p2p_send_action *act;
+ int res;
+
+ act = os_zalloc(sizeof(*act) + data_len);
+ if (act == NULL)
+ return -1;
+ act->freq = freq;
+ os_memcpy(act->dst_addr, dst, ETH_ALEN);
+ os_memcpy(act->src_addr, src, ETH_ALEN);
+ os_memcpy(act->bssid, bssid, ETH_ALEN);
+ os_memcpy(act + 1, data, data_len);
+ wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src="
+ MACSTR ", bssid=" MACSTR,
+ __func__, act->freq, wait, MAC2STR(act->dst_addr),
+ MAC2STR(act->src_addr), MAC2STR(act->bssid));
+ wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act));
+ wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len);
+
+ res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION,
+ act, sizeof(*act) + data_len);
+ os_free(act);
+ return res;
+}
+
+
+#ifdef CONFIG_IEEE80211V
+static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
+ u8 *ie, u16 *len, enum wnm_oper oper)
+{
+#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */
+ u8 buf[IEEE80211_APPIE_MAX];
+ struct ieee80211req_getset_appiebuf *tfs_ie;
+ u16 val;
+
+ wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
+ drv->iface, oper, MAC2STR(peer));
+
+ switch (oper) {
+ case WNM_SLEEP_TFS_REQ_IE_SET:
+ if (*len > IEEE80211_APPIE_MAX -
+ sizeof(struct ieee80211req_getset_appiebuf)) {
+ wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
+ return -1;
+ }
+ tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+ tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
+
+ /* Command header for driver */
+ os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+ val = oper;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+ val = *len;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+ /* copy the ie */
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
+
+ if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+ IEEE80211_APPIE_MAX)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+ "%s", __func__, strerror(errno));
+ return -1;
+ }
+ break;
+ case WNM_SLEEP_TFS_RESP_IE_ADD:
+ tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+ tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+ sizeof(struct ieee80211req_getset_appiebuf);
+ /* Command header for driver */
+ os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+ val = oper;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+ val = 0;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
+ IEEE80211_APPIE_MAX)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
+ "%s", __func__, strerror(errno));
+ return -1;
+ }
+
+ *len = tfs_ie->app_buflen;
+ os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
+ wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
+ *len);
+ break;
+ case WNM_SLEEP_TFS_RESP_IE_NONE:
+ *len = 0;
+ break;
+ case WNM_SLEEP_TFS_IE_DEL:
+ tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+ tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+ sizeof(struct ieee80211req_getset_appiebuf);
+ /* Command header for driver */
+ os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+ val = oper;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+ val = 0;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+ if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+ IEEE80211_APPIE_MAX)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+ "%s", __func__, strerror(errno));
+ return -1;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int atheros_wnm_sleep(struct atheros_driver_data *drv,
+ const u8 *peer, enum wnm_oper oper)
+{
+ u8 *data, *pos;
+ size_t dlen;
+ int ret;
+ u16 val;
+
+ wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
+ oper, MAC2STR(peer));
+
+ dlen = ETH_ALEN + 2 + 2;
+ data = os_malloc(dlen);
+ if (data == NULL)
+ return -1;
+
+ /* Command header for driver */
+ pos = data;
+ os_memcpy(pos, peer, ETH_ALEN);
+ pos += ETH_ALEN;
+
+ val = oper;
+ os_memcpy(pos, &val, 2);
+ pos += 2;
+
+ val = 0;
+ os_memcpy(pos, &val, 2);
+
+ ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
+
+ os_free(data);
+
+ return ret;
+}
+
+
+static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len)
+{
+ struct atheros_driver_data *drv = priv;
+
+ switch (oper) {
+ case WNM_SLEEP_ENTER_CONFIRM:
+ case WNM_SLEEP_ENTER_FAIL:
+ case WNM_SLEEP_EXIT_CONFIRM:
+ case WNM_SLEEP_EXIT_FAIL:
+ return atheros_wnm_sleep(drv, peer, oper);
+ case WNM_SLEEP_TFS_REQ_IE_SET:
+ case WNM_SLEEP_TFS_RESP_IE_ADD:
+ case WNM_SLEEP_TFS_RESP_IE_NONE:
+ case WNM_SLEEP_TFS_IE_DEL:
+ return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
+ default:
+ wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
+ oper);
+ return -1;
+ }
+}
+#endif /* CONFIG_IEEE80211V */
+
+
const struct wpa_driver_ops wpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = atheros_init,
@@ -1739,4 +2147,8 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
#endif /* CONFIG_IEEE80211R */
+ .send_action = atheros_send_action,
+#ifdef CONFIG_IEEE80211V
+ .wnm_oper = atheros_wnm_oper,
+#endif /* CONFIG_IEEE80211V */
};
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 67abb672..a2b34c12 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1328,8 +1328,8 @@ wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
result->ie_len = pos - (u8 *)(result + 1);
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(result);
return;
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 81856aa9..418cf1a0 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -78,6 +78,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
+ E2S(WNM);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 185ed4f0..b9e096c4 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -858,7 +858,7 @@ static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv)
os_free(b);
return NULL;
}
- results->res = os_zalloc(count * sizeof(struct wpa_scan_res *));
+ results->res = os_calloc(count, sizeof(struct wpa_scan_res *));
if (results->res == NULL) {
os_free(results);
os_free(b);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b9503f18..eeec6098 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2386,7 +2386,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct wiphy_info_data *info = arg;
int p2p_go_supported = 0, p2p_client_supported = 0;
- int p2p_concurrent = 0;
+ int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
int auth_supported = 0, connect_supported = 0;
struct wpa_driver_capa *capa = info->capa;
static struct nla_policy
@@ -2487,6 +2487,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
if (combination_has_p2p && combination_has_mgd) {
p2p_concurrent = 1;
+ if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+ p2p_multichan_concurrent = 1;
break;
}
@@ -2554,6 +2556,13 @@ broken_combination:
"interface (driver advertised support)");
capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+
+ if (p2p_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ capa->flags |=
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+ }
}
if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
@@ -2646,9 +2655,16 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
- if (!info.device_ap_sme)
+ if (!info.device_ap_sme) {
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+ /*
+ * No AP SME is currently assumed to also indicate no AP MLME
+ * in the driver/firmware.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+ }
+
drv->device_ap_sme = info.device_ap_sme;
drv->poll_command_supported = info.poll_command_supported;
drv->data_tx_status = info.data_tx_status;
@@ -3485,73 +3501,110 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(void *priv,
- struct wpa_driver_scan_params *params)
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+ struct wpa_driver_scan_params *params)
{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0, timeout;
- struct nl_msg *msg, *ssids, *freqs, *rates;
+ struct nl_msg *msg;
+ int err;
size_t i;
- drv->scan_for_auth = 0;
-
msg = nlmsg_alloc();
- ssids = nlmsg_alloc();
- freqs = nlmsg_alloc();
- rates = nlmsg_alloc();
- if (!msg || !ssids || !freqs || !rates) {
- nlmsg_free(msg);
- nlmsg_free(ssids);
- nlmsg_free(freqs);
- nlmsg_free(rates);
- return -1;
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
+ if (!msg)
+ return NULL;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
+ nl80211_cmd(drv, msg, 0, cmd);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
+ goto fail;
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid);
+ if (params->num_ssids) {
+ struct nl_msg *ssids = nlmsg_alloc();
+ if (ssids == NULL)
+ goto fail;
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid) < 0) {
+ nlmsg_free(ssids);
+ goto fail;
+ }
+ }
+ err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+ nlmsg_free(ssids);
+ if (err < 0)
+ goto fail;
}
- if (params->num_ssids)
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
if (params->extra_ies) {
wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
params->extra_ies, params->extra_ies_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies) < 0)
+ goto fail;
}
if (params->freqs) {
+ struct nl_msg *freqs = nlmsg_alloc();
+ if (freqs == NULL)
+ goto fail;
for (i = 0; params->freqs[i]; i++) {
wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
"MHz", params->freqs[i]);
- NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+ if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
+ nlmsg_free(freqs);
+ goto fail;
+ }
}
- nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+ err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
+ freqs);
+ nlmsg_free(freqs);
+ if (err < 0)
+ goto fail;
}
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ return msg;
+
+fail:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(void *priv,
+ struct wpa_driver_scan_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, timeout;
+ struct nl_msg *msg, *rates = NULL;
+
+ drv->scan_for_auth = 0;
+
+ msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+ if (!msg)
+ return -1;
+
if (params->p2p_probe) {
wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+ rates = nlmsg_alloc();
+ if (rates == NULL)
+ goto nla_put_failure;
+
/*
* Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
* by masking out everything else apart from the OFDM rates 6,
@@ -3560,7 +3613,9 @@ static int wpa_driver_nl80211_scan(void *priv,
*/
NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
"\x0c\x12\x18\x24\x30\x48\x60\x6c");
- nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+ if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
+ 0)
+ goto nla_put_failure;
NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
}
@@ -3613,9 +3668,7 @@ static int wpa_driver_nl80211_scan(void *priv,
drv, drv->ctx);
nla_put_failure:
- nlmsg_free(ssids);
nlmsg_free(msg);
- nlmsg_free(freqs);
nlmsg_free(rates);
return ret;
}
@@ -3634,8 +3687,10 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0;
- struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+ int ret = -1;
+ struct nl_msg *msg;
+ struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
+ struct nl_msg *match_set_rssi = NULL;
size_t i;
#ifdef ANDROID
@@ -3643,30 +3698,18 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
return android_pno_start(bss, params);
#endif /* ANDROID */
- msg = nlmsg_alloc();
- ssids = nlmsg_alloc();
- freqs = nlmsg_alloc();
- if (!msg || !ssids || !freqs) {
- nlmsg_free(msg);
- nlmsg_free(ssids);
- nlmsg_free(freqs);
- return -1;
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+ if (!msg)
+ goto nla_put_failure;
NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
- if (drv->num_filter_ssids &&
- (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
+ if ((drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+ params->filter_rssi) {
match_sets = nlmsg_alloc();
+ if (match_sets == NULL)
+ goto nla_put_failure;
for (i = 0; i < drv->num_filter_ssids; i++) {
wpa_hexdump_ascii(MSG_MSGDUMP,
@@ -3675,45 +3718,35 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
drv->filter_ssids[i].ssid_len);
match_set_ssid = nlmsg_alloc();
- nla_put(match_set_ssid,
+ if (match_set_ssid == NULL)
+ goto nla_put_failure;
+ NLA_PUT(match_set_ssid,
NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
drv->filter_ssids[i].ssid_len,
drv->filter_ssids[i].ssid);
- nla_put_nested(match_sets, i + 1, match_set_ssid);
-
- nlmsg_free(match_set_ssid);
+ if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
+ 0)
+ goto nla_put_failure;
}
- nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
- match_sets);
- nlmsg_free(match_sets);
- }
-
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid);
- }
- if (params->num_ssids)
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
- if (params->extra_ies) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
- params->extra_ies, params->extra_ies_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies);
- }
-
- if (params->freqs) {
- for (i = 0; params->freqs[i]; i++) {
- wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
- "MHz", params->freqs[i]);
- NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+ if (params->filter_rssi) {
+ match_set_rssi = nlmsg_alloc();
+ if (match_set_rssi == NULL)
+ goto nla_put_failure;
+ NLA_PUT_U32(match_set_rssi,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi);
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan RSSI filter %d dBm",
+ params->filter_rssi);
+ if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
+ goto nla_put_failure;
}
- nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+
+ if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+ match_sets) < 0)
+ goto nla_put_failure;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3731,9 +3764,10 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
"scan interval %d msec", ret, interval);
nla_put_failure:
- nlmsg_free(ssids);
+ nlmsg_free(match_set_ssid);
+ nlmsg_free(match_sets);
+ nlmsg_free(match_set_rssi);
nlmsg_free(msg);
- nlmsg_free(freqs);
return ret;
}
@@ -3981,8 +4015,8 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
return NL_SKIP;
}
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
return NL_SKIP;
@@ -4185,6 +4219,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_ALG_GCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4325,6 +4363,9 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
case WPA_ALG_CCMP:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_ALG_GCMP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4777,7 +4818,9 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
return NL_SKIP;
nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
- mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
+ mode = os_realloc_array(phy_info->modes,
+ *phy_info->num_modes + 1,
+ sizeof(*mode));
if (!mode)
return NL_SKIP;
phy_info->modes = mode;
@@ -4836,7 +4879,8 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
mode->num_channels++;
}
- mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
+ mode->channels = os_calloc(mode->num_channels,
+ sizeof(struct hostapd_channel_data));
if (!mode->channels)
return NL_SKIP;
@@ -4898,7 +4942,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
mode->num_rates++;
}
- mode->rates = os_zalloc(mode->num_rates * sizeof(int));
+ mode->rates = os_calloc(mode->num_rates, sizeof(int));
if (!mode->rates)
return NL_SKIP;
@@ -4943,7 +4987,7 @@ wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
if (mode11g_idx < 0)
return modes; /* 2.4 GHz band not supported at all */
- nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+ nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
if (nmodes == NULL)
return modes; /* Could not add 802.11b mode */
@@ -5457,6 +5501,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
num_suites = 0;
if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+ if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
@@ -5473,6 +5519,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_CIPHER_GCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_CIPHER_TKIP:
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_TKIP);
@@ -5643,7 +5693,8 @@ static int wpa_driver_nl80211_sta_add(void *priv,
NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
(params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
WMM_QOSINFO_STA_SP_MASK);
- nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+ if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
+ goto nla_put_failure;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6746,6 +6797,9 @@ skip_auth_type:
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6767,6 +6821,9 @@ skip_auth_type:
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6909,6 +6966,9 @@ static int wpa_driver_nl80211_associate(
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6931,6 +6991,9 @@ static int wpa_driver_nl80211_associate(
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7084,6 +7147,11 @@ done:
return ret;
}
+ if (is_p2p_interface(nlmode))
+ nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+ else if (drv->disabled_11b_rates)
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
/* Setup additional AP mode functionality if needed */
@@ -7336,7 +7404,6 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
- [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
};
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -7372,9 +7439,6 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
if (stats[NL80211_STA_INFO_TX_PACKETS])
data->tx_packets =
nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
- if (stats[NL80211_STA_INFO_TX_FAILED])
- data->tx_retry_failed =
- nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
return NL_SKIP;
}
@@ -7586,8 +7650,8 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
else
old = NULL;
- drv->if_indices = os_realloc(old,
- sizeof(int) * (drv->num_if_indices + 1));
+ drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+ sizeof(int));
if (!drv->if_indices) {
if (!old)
drv->if_indices = drv->default_if_indices;
@@ -7651,7 +7715,10 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
bridge_ifname, name) < 0)
return -1;
}
- linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
+ if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+ "interface %s up", name);
+ }
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -8377,7 +8444,9 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
"(%s)", ret, strerror(-ret));
- }
+ } else
+ drv->disabled_11b_rates = disabled;
+
return ret;
nla_put_failure:
@@ -8470,6 +8539,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg, *cqm = NULL;
+ int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
"hysteresis=%d", threshold, hysteresis);
@@ -8484,20 +8554,20 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
cqm = nlmsg_alloc();
if (cqm == NULL)
- return -1;
+ goto nla_put_failure;
NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
- nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
+ if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
+ goto nla_put_failure;
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
- return 0;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
nla_put_failure:
nlmsg_free(cqm);
nlmsg_free(msg);
- return -1;
+ return ret;
}
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index c8916f06..9481cbf8 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -152,7 +152,7 @@ wpa_driver_privsep_get_scan_results2(void *priv)
return NULL;
}
- results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
+ results->res = os_calloc(num, sizeof(struct wpa_scan_res *));
if (results->res == NULL) {
os_free(results);
os_free(buf);
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index f011651f..e7bf1956 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1478,7 +1478,7 @@ static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
if (res == NULL)
return NULL;
- res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
+ res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
if (res->res == NULL) {
os_free(res);
return NULL;
@@ -2570,15 +2570,14 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
*num_modes = 3;
*flags = 0;
- modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+ modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes));
if (modes == NULL)
return NULL;
modes[0].mode = HOSTAPD_MODE_IEEE80211G;
modes[0].num_channels = 11;
modes[0].num_rates = 12;
- modes[0].channels =
- os_zalloc(11 * sizeof(struct hostapd_channel_data));
- modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
+ modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+ modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int));
if (modes[0].channels == NULL || modes[0].rates == NULL)
goto fail;
for (i = 0; i < 11; i++) {
@@ -2602,9 +2601,8 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
modes[1].mode = HOSTAPD_MODE_IEEE80211B;
modes[1].num_channels = 11;
modes[1].num_rates = 4;
- modes[1].channels =
- os_zalloc(11 * sizeof(struct hostapd_channel_data));
- modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int));
+ modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+ modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int));
if (modes[1].channels == NULL || modes[1].rates == NULL)
goto fail;
for (i = 0; i < 11; i++) {
@@ -2620,8 +2618,8 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
modes[2].mode = HOSTAPD_MODE_IEEE80211A;
modes[2].num_channels = 1;
modes[2].num_rates = 8;
- modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
- modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int));
+ modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data));
+ modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int));
if (modes[2].channels == NULL || modes[2].rates == NULL)
goto fail;
modes[2].channels[0].chan = 60;
@@ -2822,17 +2820,19 @@ static int wpa_driver_test_probe_req_report(void *priv, int report)
static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
if (!drv->p2p)
return -1;
- return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL);
+ return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0);
}
static int wpa_driver_test_p2p_stop_find(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
if (!drv->p2p)
return -1;
@@ -2843,7 +2843,8 @@ static int wpa_driver_test_p2p_stop_find(void *priv)
static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
if (!drv->p2p)
return -1;
@@ -2857,7 +2858,8 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
unsigned int force_freq,
int persistent_group)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d "
"go_intent=%d "
"own_interface_addr=" MACSTR " force_freq=%u "
@@ -2874,7 +2876,8 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")",
__func__, MAC2STR(peer_addr));
if (!drv->p2p)
@@ -2886,7 +2889,8 @@ static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
static int wpa_driver_test_p2p_group_formation_failed(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
if (!drv->p2p)
return -1;
@@ -2898,7 +2902,8 @@ static int wpa_driver_test_p2p_group_formation_failed(void *priv)
static int wpa_driver_test_p2p_set_params(void *priv,
const struct p2p_params *params)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
if (!drv->p2p)
return -1;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 068e4162..bd37ca14 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -40,10 +40,7 @@ static int wpa_driver_wext_get_range(void *priv);
static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
-#ifdef ANDROID
-extern int wpa_driver_wext_combo_scan(void *priv,
- struct wpa_driver_scan_params *params);
-#endif
+
int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
int idx, u32 value)
@@ -481,19 +478,10 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
drv->assoc_req_ies = NULL;
os_free(drv->assoc_resp_ies);
drv->assoc_resp_ies = NULL;
-#ifdef ANDROID
- if (!drv->skip_disconnect) {
- drv->skip_disconnect = 1;
-#endif
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
NULL);
-#ifdef ANDROID
- }
-#endif
+
} else {
-#ifdef ANDROID
- drv->skip_disconnect = 0;
-#endif
wpa_driver_wext_event_assoc_ies(drv);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
NULL);
@@ -875,7 +863,6 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
#ifdef ANDROID
drv->errors = 0;
drv->driver_is_started = TRUE;
- drv->skip_disconnect = 0;
drv->bgscan_enabled = 0;
#endif /* ANDROID */
@@ -1039,13 +1026,6 @@ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
const u8 *ssid = params->ssids[0].ssid;
size_t ssid_len = params->ssids[0].ssid_len;
-#ifdef ANDROID
- if (drv->capa.max_scan_ssids > 1) {
- ret = wpa_driver_wext_combo_scan(priv, params);
- goto scan_out;
- }
-#endif
-
if (ssid_len > IW_ESSID_MAX_SIZE) {
wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
__FUNCTION__, (unsigned long) ssid_len);
@@ -1071,9 +1051,6 @@ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
ret = -1;
}
-#ifdef ANDROID
-scan_out:
-#endif
/* Not all drivers generate "scan completed" wireless event, so try to
* read results after a timeout. */
timeout = 10;
@@ -1437,8 +1414,8 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
if (data->ie)
os_memcpy(pos, data->ie, data->ie_len);
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
return;
@@ -1608,11 +1585,7 @@ static int wpa_driver_wext_get_range(void *priv)
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
-#ifdef ANDROID
- drv->capa.max_scan_ssids = WEXT_CSCAN_AMOUNT;
-#else
drv->capa.max_scan_ssids = 1;
-#endif
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
"flags 0x%x",
@@ -2084,9 +2057,7 @@ int wpa_driver_wext_associate(void *priv,
int value;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-#ifdef ANDROID
- drv->skip_disconnect = 0;
-#endif
+
if (drv->cfg80211) {
/*
* Stop cfg80211 from trying to associate before we are done
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index 7e0b28b6..c4a5bc99 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -48,7 +48,6 @@ struct wpa_driver_wext_data {
#ifdef ANDROID
int errors;
int driver_is_started;
- int skip_disconnect;
int bgscan_enabled;
#endif /* ANDROID */
};
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 0cc81f9c..c7a98d31 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -30,7 +30,7 @@ NEED_RFKILL=y
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -142,6 +142,28 @@ ifdef NEED_RFKILL
DRV_OBJS += ../src/drivers/rfkill.o
endif
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ endif
+
+ ifdef CONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
+ DRV_LIBS += -lnl-route
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+ endif
+endif
+endif
+endif
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 1d7129cd..23fcbb7c 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -30,7 +30,7 @@ NEED_RFKILL=y
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -146,6 +146,29 @@ ifdef CONFIG_DRIVER_CUSTOM
DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
endif
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ endif
+
+ ifdef CONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
+ DRV_LIBS += -lnl-route
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+ endif
+endif
+endif
+endif
+
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
DRV_WPA_CFLAGS += $(DRV_CFLAGS)
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 940b69af..4380428f 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -45,8 +45,9 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
ret = errno ? -errno : -999;
- wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
- ifname, strerror(errno));
+ wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
+ "%s",
+ ifname, dev_up ? "UP" : "DOWN", strerror(errno));
return ret;
}
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 74cc55c1..2f387880 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -771,6 +771,9 @@ enum nl80211_commands {
* @NL80211_ATTR_IFNAME: network interface name
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
*
+ * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices
+ * that don't have a netdev (u64)
+ *
* @NL80211_ATTR_MAC: MAC address (various uses)
*
* @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
@@ -1242,6 +1245,12 @@ enum nl80211_commands {
* @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
* or 0 to disable background scan.
*
+ * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from
+ * userspace. If unset it is assumed the hint comes directly from
+ * a user. If set code could specify exactly what type of source
+ * was used to provide the hint. For the different types of
+ * allowed user regulatory hints see nl80211_user_reg_hint_type.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1493,6 +1502,10 @@ enum nl80211_attrs {
NL80211_ATTR_BG_SCAN_PERIOD,
+ NL80211_ATTR_WDEV,
+
+ NL80211_ATTR_USER_REG_HINT_TYPE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1545,6 +1558,8 @@ enum nl80211_attrs {
/* default RSSI threshold for scan results if none specified. */
#define NL80211_SCAN_RSSI_THOLD_OFF -300
+#define NL80211_CQM_TXE_MAX_INTVL 1800
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -1638,12 +1653,20 @@ struct nl80211_sta_flag_update {
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
* when getting information about the bitrate of a station.
+ * There are 2 attributes for bitrate, a legacy one that represents
+ * a 16-bit value, and new one that represents a 32-bit value.
+ * If the rate value fits into 16 bit, both attributes are reported
+ * with the same value. If the rate is too high to fit into 16 bits
+ * (>6.5535Gbps) only 32-bit attribute is included.
+ * User space tools encouraged to use the 32-bit attribute and fall
+ * back to the 16-bit one for compatibility with older kernels.
*
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
* @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
@@ -1653,6 +1676,7 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_MCS,
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
+ NL80211_RATE_INFO_BITRATE32,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -2045,6 +2069,26 @@ enum nl80211_dfs_regions {
};
/**
+ * enum nl80211_user_reg_hint_type - type of user regulatory hint
+ *
+ * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always
+ * assumed if the attribute is not set.
+ * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular
+ * base station. Device drivers that have been tested to work
+ * properly to support this type of hint can enable these hints
+ * by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature
+ * capability on the struct wiphy. The wireless core will
+ * ignore all cell base station hints until at least one device
+ * present has been registered with the wireless core that
+ * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
+ * supported feature.
+ */
+enum nl80211_user_reg_hint_type {
+ NL80211_USER_REG_HINT_USER = 0,
+ NL80211_USER_REG_HINT_CELL_BASE = 1,
+};
+
+/**
* enum nl80211_survey_info - survey information
*
* These attribute types are used with %NL80211_ATTR_SURVEY_INFO
@@ -2575,6 +2619,17 @@ enum nl80211_ps_state {
* @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
* @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
* consecutive packets were not acknowledged by the peer
+ * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures
+ * during the given %NL80211_ATTR_CQM_TXE_INTVL before an
+ * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and
+ * %NL80211_ATTR_CQM_TXE_PKTS is generated.
+ * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given
+ * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is
+ * checked.
+ * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic
+ * interval in which %NL80211_ATTR_CQM_TXE_PKTS and
+ * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
+ * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
* @NL80211_ATTR_CQM_MAX: highest key attribute
*/
@@ -2584,6 +2639,9 @@ enum nl80211_attr_cqm {
NL80211_ATTR_CQM_RSSI_HYST,
NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+ NL80211_ATTR_CQM_TXE_RATE,
+ NL80211_ATTR_CQM_TXE_PKTS,
+ NL80211_ATTR_CQM_TXE_INTVL,
/* keep last */
__NL80211_ATTR_CQM_AFTER_LAST,
@@ -2933,11 +2991,15 @@ enum nl80211_ap_sme_features {
* @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
* @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
* the connected inactive stations in AP mode.
+ * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
+ * to work properly to suppport receiving regulatory hints from
+ * cellular base stations.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
+ NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
};
/**
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 0d6ef931..7b077cb9 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,6 +13,41 @@
#include "eap_common.h"
/**
+ * eap_hdr_len_valid - Validate EAP header length field
+ * @msg: EAP frame (starting with EAP header)
+ * @min_payload: Minimum payload length needed
+ * Returns: 1 for valid header, 0 for invalid
+ *
+ * This is a helper function that does minimal validation of EAP messages. The
+ * length field is verified to be large enough to include the header and not
+ * too large to go beyond the end of the buffer.
+ */
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
+{
+ const struct eap_hdr *hdr;
+ size_t len;
+
+ if (msg == NULL)
+ return 0;
+
+ hdr = wpabuf_head(msg);
+
+ if (wpabuf_len(msg) < sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+ return 0;
+ }
+
+ len = be_to_host16(hdr->length);
+ if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
+ wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
* eap_hdr_validate - Validate EAP header
* @vendor: Expected EAP Vendor-Id (0 = IETF)
* @eap_type: Expected EAP type number
@@ -35,19 +70,11 @@ const u8 * eap_hdr_validate(int vendor, EapType eap_type,
const u8 *pos;
size_t len;
- hdr = wpabuf_head(msg);
-
- if (wpabuf_len(msg) < sizeof(*hdr)) {
- wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+ if (!eap_hdr_len_valid(msg, 1))
return NULL;
- }
+ hdr = wpabuf_head(msg);
len = be_to_host16(hdr->length);
- if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) {
- wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
- return NULL;
- }
-
pos = (const u8 *) (hdr + 1);
if (*pos == EAP_TYPE_EXPANDED) {
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index 73f27972..8850c1fe 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "wpabuf.h"
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
const struct wpabuf *msg, size_t *plen);
struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 360193a9..0d247c4d 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -71,9 +71,13 @@ typedef enum {
enum {
EAP_VENDOR_IETF = 0,
EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
- EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
+ EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */,
+ EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */
};
+#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP
+#define EAP_VENDOR_TYPE_UNAUTH_TLS 1
+
#define EAP_MSK_LEN 64
#define EAP_EMSK_LEN 64
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 8b43be43..ba973a52 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -20,6 +20,7 @@
#include "common.h"
#include "pcsc_funcs.h"
#include "state_machine.h"
+#include "ext_password.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "common/wpa_ctrl.h"
@@ -93,6 +94,9 @@ static void eap_notify_status(struct eap_sm *sm, const char *status,
static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
{
+ ext_password_free(sm->ext_pw_buf);
+ sm->ext_pw_buf = NULL;
+
if (sm->m == NULL || sm->eap_method_priv == NULL)
return;
@@ -185,6 +189,12 @@ SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ /*
+ * RFC 4137 does not describe clearing of idleWhile here, but doing so
+ * allows the timer tick to be stopped more quickly when EAP is not in
+ * use.
+ */
+ eapol_set_int(sm, EAPOL_idleWhile, 0);
}
@@ -346,6 +356,8 @@ SM_STATE(EAP, METHOD)
}
eapReqData = eapol_get_eapReqData(sm);
+ if (!eap_hdr_len_valid(eapReqData, 1))
+ return;
/*
* Get ignore, methodState, decision, allowNotifications, and
@@ -434,6 +446,8 @@ SM_STATE(EAP, IDENTITY)
SM_ENTRY(EAP, IDENTITY);
eapReqData = eapol_get_eapReqData(sm);
+ if (!eap_hdr_len_valid(eapReqData, 1))
+ return;
eap_sm_processIdentity(sm, eapReqData);
wpabuf_free(sm->eapRespData);
sm->eapRespData = NULL;
@@ -450,6 +464,8 @@ SM_STATE(EAP, NOTIFICATION)
SM_ENTRY(EAP, NOTIFICATION);
eapReqData = eapol_get_eapReqData(sm);
+ if (!eap_hdr_len_valid(eapReqData, 1))
+ return;
eap_sm_processNotify(sm, eapReqData);
wpabuf_free(sm->eapRespData);
sm->eapRespData = NULL;
@@ -867,13 +883,17 @@ static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
{
- const struct eap_hdr *hdr = wpabuf_head(req);
- const u8 *pos = (const u8 *) (hdr + 1);
- pos++;
+ const u8 *pos;
+ size_t msg_len;
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
"EAP authentication started");
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
+ &msg_len);
+ if (pos == NULL)
+ return;
+
/*
* RFC 3748 - 5.1: Identity
* Data field may contain a displayable message in UTF-8. If this
@@ -884,7 +904,7 @@ static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
/* TODO: could save displayable message so that it can be shown to the
* user in case of interaction is required */
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
- pos, be_to_host16(hdr->length) - 5);
+ pos, msg_len);
}
@@ -1915,6 +1935,27 @@ const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
}
+static int eap_get_ext_password(struct eap_sm *sm,
+ struct eap_peer_config *config)
+{
+ char *name;
+
+ if (config->password == NULL)
+ return -1;
+
+ name = os_zalloc(config->password_len + 1);
+ if (name == NULL)
+ return -1;
+ os_memcpy(name, config->password, config->password_len);
+
+ ext_password_free(sm->ext_pw_buf);
+ sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
+ os_free(name);
+
+ return sm->ext_pw_buf == NULL ? -1 : 0;
+}
+
+
/**
* eap_get_config_password - Get password from the network configuration
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
@@ -1926,6 +1967,14 @@ const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
return NULL;
+
+ if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if (eap_get_ext_password(sm, config) < 0)
+ return NULL;
+ *len = wpabuf_len(sm->ext_pw_buf);
+ return wpabuf_head(sm->ext_pw_buf);
+ }
+
*len = config->password_len;
return config->password;
}
@@ -1945,6 +1994,14 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
return NULL;
+
+ if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if (eap_get_ext_password(sm, config) < 0)
+ return NULL;
+ *len = wpabuf_len(sm->ext_pw_buf);
+ return wpabuf_head(sm->ext_pw_buf);
+ }
+
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
@@ -2256,3 +2313,11 @@ int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
return 1;
}
+
+
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
+{
+ ext_password_free(sm->ext_pw_buf);
+ sm->ext_pw_buf = NULL;
+ sm->ext_pw = ext;
+}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 6e87475d..cf58608c 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -306,6 +306,9 @@ void eap_invalidate_cached_session(struct eap_sm *sm);
int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
+struct ext_password_data;
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
+
#endif /* IEEE8021X_EAPOL */
#endif /* EAP_H */
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index a6f6f4cf..a08543e1 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -619,6 +619,7 @@ struct eap_peer_config {
int fragment_size;
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
+#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
/**
* flags - Network configuration flags (bitfield)
*
@@ -626,6 +627,8 @@ struct eap_peer_config {
* for the network parameters.
* bit 0 = password is represented as a 16-byte NtPasswordHash value
* instead of plaintext password
+ * bit 1 = password is stored in external storage; the value in the
+ * password field is the name of that external entry
*/
u32 flags;
};
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 31d9f7cf..7ca5288c 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -169,7 +169,7 @@ static void * eap_fast_init(struct eap_sm *sm)
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_NONE;
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_FAST)) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
eap_fast_deinit(sm, data);
return NULL;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 3318b811..dd943174 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -330,6 +330,9 @@ struct eap_sm {
struct wps_context *wps;
int prev_failure;
+
+ struct ext_password_data *ext_pw;
+ struct wpabuf *ext_pw_buf;
};
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eap_peer/eap_md5.c b/src/eap_peer/eap_md5.c
index e3484151..d06befae 100644
--- a/src/eap_peer/eap_md5.c
+++ b/src/eap_peer/eap_md5.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -86,7 +86,13 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
id = eap_get_id(resp);
rpos = wpabuf_put(resp, CHAP_MD5_LEN);
- chap_md5(id, password, password_len, challenge, challenge_len, rpos);
+ if (chap_md5(id, password, password_len, challenge, challenge_len,
+ rpos)) {
+ wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+ ret->ignore = TRUE;
+ wpabuf_free(resp);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
return resp;
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index ff9f50db..4994ff1c 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -85,6 +85,7 @@ static inline int eap_peer_method_unload(struct eap_method *method)
/* EAP peer method registration calls for statically linked in methods */
int eap_peer_md5_register(void);
int eap_peer_tls_register(void);
+int eap_peer_unauth_tls_register(void);
int eap_peer_mschapv2_register(void);
int eap_peer_peap_register(void);
int eap_peer_ttls_register(void);
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 3b0a116b..fb6c282a 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -304,7 +304,9 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm,
"EAP-MSCHAPV2: Password changed successfully");
data->prev_error = 0;
os_free(config->password);
- if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
+ if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ /* TODO: update external storage */
+ } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
config->password = os_malloc(16);
config->password_len = 16;
if (config->password) {
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 0caa77e2..7fff1458 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -159,7 +159,7 @@ static void * eap_peap_init(struct eap_sm *sm)
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_NONE;
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
eap_peap_deinit(sm, data);
return NULL;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ed52fb69..061a72b1 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -22,6 +22,7 @@ struct eap_tls_data {
struct eap_ssl_data ssl;
u8 *key_data;
void *ssl_ctx;
+ u8 eap_type;
};
@@ -44,7 +45,7 @@ static void * eap_tls_init(struct eap_sm *sm)
data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
sm->ssl_ctx;
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
if (config->engine) {
@@ -62,8 +63,37 @@ static void * eap_tls_init(struct eap_sm *sm)
return NULL;
}
+ data->eap_type = EAP_TYPE_TLS;
+
+ return data;
+}
+
+
+#ifdef EAP_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+ sm->ssl_ctx;
+
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
+ EAP_UNAUTH_TLS_TYPE)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_deinit(sm, data);
+ return NULL;
+ }
+
+ data->eap_type = EAP_UNAUTH_TLS_TYPE;
+
return data;
}
+#endif /* EAP_UNAUTH_TLS */
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
@@ -109,7 +139,7 @@ static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
return resp;
}
- return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
+ return eap_peer_tls_build_ack(id, data->eap_type, 0);
}
@@ -149,7 +179,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
const u8 *pos;
struct eap_tls_data *data = priv;
- pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
+ pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
reqData, &left, &flags);
if (pos == NULL)
return NULL;
@@ -162,8 +192,8 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
}
resp = NULL;
- res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
- pos, left, &resp);
+ res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
+ id, pos, left, &resp);
if (res < 0) {
return eap_tls_failure(sm, data, ret, res, resp, id);
@@ -174,7 +204,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
if (res == 1) {
wpabuf_free(resp);
- return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
+ return eap_peer_tls_build_ack(id, data->eap_type, 0);
}
return resp;
@@ -285,3 +315,34 @@ int eap_peer_tls_register(void)
eap_peer_method_free(eap);
return ret;
}
+
+
+#ifdef EAP_UNAUTH_TLS
+int eap_peer_unauth_tls_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_unauth_tls_init;
+ eap->deinit = eap_tls_deinit;
+ eap->process = eap_tls_process;
+ eap->isKeyAvailable = eap_tls_isKeyAvailable;
+ eap->getKey = eap_tls_getKey;
+ eap->get_status = eap_tls_get_status;
+ eap->has_reauth_data = eap_tls_has_reauth_data;
+ eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+ eap->init_for_reauth = eap_tls_init_for_reauth;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
+#endif /* EAP_UNAUTH_TLS */
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 69e83d9b..7eefe8c9 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -16,6 +16,18 @@
#include "eap_config.h"
+static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier)
+{
+ if (type == EAP_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
+ code, identifier);
+ return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+ identifier);
+}
+
+
static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
const u8 **data, size_t *data_len)
{
@@ -48,6 +60,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
if (os_strstr(txt, "tls_disable_time_checks=1"))
params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
+ if (os_strstr(txt, "tls_disable_session_ticket=1"))
+ params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+ if (os_strstr(txt, "tls_disable_session_ticket=0"))
+ params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
}
@@ -99,6 +115,18 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
struct eap_peer_config *config, int phase2)
{
os_memset(params, 0, sizeof(*params));
+ if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
+ /*
+ * Some deployed authentication servers seem to be unable to
+ * handle the TLS Session Ticket extension (they are supposed
+ * to ignore unrecognized TLS extensions, but end up rejecting
+ * the ClientHello instead). As a workaround, disable use of
+ * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
+ * EAP-TTLS (EAP-FAST uses session ticket, so any server that
+ * supports EAP-FAST does not need this workaround).
+ */
+ params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+ }
if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
@@ -182,13 +210,14 @@ static int eap_tls_init_connection(struct eap_sm *sm,
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @data: Data for TLS processing
* @config: Pointer to the network configuration
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
* Returns: 0 on success, -1 on failure
*
* This function is used to initialize shared TLS functionality for EAP-TLS,
* EAP-PEAP, EAP-TTLS, and EAP-FAST.
*/
int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- struct eap_peer_config *config)
+ struct eap_peer_config *config, u8 eap_type)
{
struct tls_connection_params params;
@@ -196,6 +225,7 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
return -1;
data->eap = sm;
+ data->eap_type = eap_type;
data->phase2 = sm->init_phase2;
data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
sm->ssl_ctx;
@@ -259,7 +289,9 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len)
{
+#ifndef CONFIG_FIPS
struct tls_keys keys;
+#endif /* CONFIG_FIPS */
u8 *rnd = NULL, *out;
out = os_malloc(len);
@@ -271,6 +303,7 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
== 0)
return out;
+#ifndef CONFIG_FIPS
/*
* TLS library did not support key generation, so get the needed TLS
* session parameters and use an internal implementation of TLS PRF to
@@ -299,6 +332,7 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
return out;
fail:
+#endif /* CONFIG_FIPS */
os_free(out);
os_free(rnd);
return NULL;
@@ -516,9 +550,8 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
length_included = 1;
}
- *out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
- 1 + length_included * 4 + len,
- EAP_CODE_RESPONSE, id);
+ *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
+ EAP_CODE_RESPONSE, id);
if (*out_data == NULL)
return -1;
@@ -656,8 +689,7 @@ struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
{
struct wpabuf *resp;
- resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE,
- id);
+ resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
if (resp == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
@@ -750,7 +782,13 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
return NULL;
}
- pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left);
+ if (eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
+ &left);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
+ &left);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
@@ -946,8 +984,8 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config,
"method '%s'", start);
} else {
num_methods++;
- _methods = os_realloc(methods,
- num_methods * sizeof(*methods));
+ _methods = os_realloc_array(methods, num_methods,
+ sizeof(*methods));
if (_methods == NULL) {
os_free(methods);
os_free(buf);
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 771385bc..91d3a25a 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -68,6 +68,11 @@ struct eap_ssl_data {
* ssl_ctx - TLS library context to use for the connection
*/
void *ssl_ctx;
+
+ /**
+ * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ */
+ u8 eap_type;
};
@@ -80,9 +85,12 @@ struct eap_ssl_data {
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- struct eap_peer_config *config);
+ struct eap_peer_config *config, u8 eap_type);
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len);
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e09f5e50..9360a424 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -110,7 +110,7 @@ static void * eap_ttls_init(struct eap_sm *sm)
data->phase2_eap_type.method = EAP_TYPE_NONE;
}
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
eap_ttls_deinit(sm, data);
return NULL;
@@ -401,6 +401,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
struct eap_method_ret *ret,
struct wpabuf **resp)
{
+#ifdef EAP_MSCHAPv2
struct wpabuf *msg;
u8 *buf, *pos, *challenge, *peer_challenge;
const u8 *identity, *password;
@@ -488,6 +489,10 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
}
return 0;
+#else /* EAP_MSCHAPv2 */
+ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+ return -1;
+#endif /* EAP_MSCHAPv2 */
}
@@ -1042,6 +1047,7 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
struct eap_method_ret *ret,
struct ttls_parse_avp *parse)
{
+#ifdef EAP_MSCHAPv2
if (parse->mschapv2_error) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
"MS-CHAP-Error - failed");
@@ -1090,6 +1096,10 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
* with EAP-Success after this.
*/
return 1;
+#else /* EAP_MSCHAPv2 */
+ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+ return -1;
+#endif /* EAP_MSCHAPv2 */
}
diff --git a/src/eap_peer/eap_vendor_test.c b/src/eap_peer/eap_vendor_test.c
index f23b9d2a..040d1e7f 100644
--- a/src/eap_peer/eap_vendor_test.c
+++ b/src/eap_peer/eap_vendor_test.c
@@ -19,7 +19,7 @@
#endif /* TEST_PENDING_REQUEST */
-#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
#define EAP_VENDOR_TYPE 0xfcfbfaf9
diff --git a/src/eap_peer/mschapv2.c b/src/eap_peer/mschapv2.c
index 67dbadb7..37e6735e 100644
--- a/src/eap_peer/mschapv2.c
+++ b/src/eap_peer/mschapv2.c
@@ -63,22 +63,28 @@ int mschapv2_derive_response(const u8 *identity, size_t identity_len,
if (pwhash) {
wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
password, password_len);
- generate_nt_response_pwhash(auth_challenge, peer_challenge,
- username, username_len,
- password, nt_response);
- generate_authenticator_response_pwhash(
- password, peer_challenge, auth_challenge,
- username, username_len, nt_response, auth_response);
+ if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
+ username, username_len,
+ password, nt_response) ||
+ generate_authenticator_response_pwhash(
+ password, peer_challenge, auth_challenge,
+ username, username_len, nt_response,
+ auth_response))
+ return -1;
} else {
wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
password, password_len);
- generate_nt_response(auth_challenge, peer_challenge,
- username, username_len,
- password, password_len, nt_response);
- generate_authenticator_response(password, password_len,
- peer_challenge, auth_challenge,
- username, username_len,
- nt_response, auth_response);
+ if (generate_nt_response(auth_challenge, peer_challenge,
+ username, username_len,
+ password, password_len,
+ nt_response) ||
+ generate_authenticator_response(password, password_len,
+ peer_challenge,
+ auth_challenge,
+ username, username_len,
+ nt_response,
+ auth_response))
+ return -1;
}
wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
nt_response, MSCHAPV2_NT_RESPONSE_LEN);
@@ -94,7 +100,8 @@ int mschapv2_derive_response(const u8 *identity, size_t identity_len,
hash_nt_password_hash(password_hash, password_hash_hash))
return -1;
}
- get_master_key(password_hash_hash, nt_response, master_key);
+ if (get_master_key(password_hash_hash, nt_response, master_key))
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
master_key, MSCHAPV2_MASTER_KEY_LEN);
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index 9667cf47..bc810a9b 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -26,6 +26,7 @@ const char * eap_server_get_name(int vendor, EapType type);
int eap_server_identity_register(void);
int eap_server_md5_register(void);
int eap_server_tls_register(void);
+int eap_server_unauth_tls_register(void);
int eap_server_mschapv2_register(void);
int eap_server_peap_register(void);
int eap_server_tlv_register(void);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 44c089fa..15f7e228 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -275,6 +275,11 @@ SM_STATE(EAP, INTEGRITY_CHECK)
{
SM_ENTRY(EAP, INTEGRITY_CHECK);
+ if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
+ sm->ignore = TRUE;
+ return;
+ }
+
if (sm->m->check) {
sm->ignore = sm->m->check(sm, sm->eap_method_priv,
sm->eap_if.eapRespData);
@@ -309,6 +314,9 @@ SM_STATE(EAP, METHOD_RESPONSE)
{
SM_ENTRY(EAP, METHOD_RESPONSE);
+ if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
+ return;
+
sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
if (sm->m->isDone(sm, sm->eap_method_priv)) {
eap_sm_Policy_update(sm, NULL, 0);
@@ -380,6 +388,9 @@ SM_STATE(EAP, NAK)
}
sm->m = NULL;
+ if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
+ return;
+
nak = wpabuf_head(sm->eap_if.eapRespData);
if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
len = be_to_host16(nak->length);
diff --git a/src/eap_server/eap_server_md5.c b/src/eap_server/eap_server_md5.c
index f4bb2610..5a5e2907 100644
--- a/src/eap_server/eap_server_md5.c
+++ b/src/eap_server/eap_server_md5.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-MD5 server
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -119,8 +119,12 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN);
id = eap_get_id(respData);
- chap_md5(id, sm->user->password, sm->user->password_len,
- data->challenge, CHALLENGE_LEN, hash);
+ if (chap_md5(id, sm->user->password, sm->user->password_len,
+ data->challenge, CHALLENGE_LEN, hash)) {
+ wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+ data->state = FAILURE;
+ return;
+ }
if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) {
wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index d34ef41c..447f47cf 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -21,6 +21,7 @@ struct eap_tls_data {
struct eap_ssl_data ssl;
enum { START, CONTINUE, SUCCESS, FAILURE } state;
int established;
+ u8 eap_type;
};
@@ -65,8 +66,32 @@ static void * eap_tls_init(struct eap_sm *sm)
return NULL;
}
+ data->eap_type = EAP_TYPE_TLS;
+
+ return data;
+}
+
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = START;
+
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_reset(sm, data);
+ return NULL;
+ }
+
+ data->eap_type = EAP_UNAUTH_TLS_TYPE;
return data;
}
+#endif /* EAP_SERVER_UNAUTH_TLS */
static void eap_tls_reset(struct eap_sm *sm, void *priv)
@@ -84,8 +109,7 @@ static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
{
struct wpabuf *req;
- req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
- id);
+ req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
"request");
@@ -107,11 +131,11 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
struct wpabuf *res;
if (data->ssl.state == FRAG_ACK) {
- return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
+ return eap_server_tls_build_ack(id, data->eap_type, 0);
}
if (data->ssl.state == WAIT_FRAG_ACK) {
- res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
+ res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
id);
goto check_established;
}
@@ -129,7 +153,7 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
return NULL;
}
- res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
+ res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
check_established:
if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
@@ -146,10 +170,17 @@ check_established:
static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
+ struct eap_tls_data *data = priv;
const u8 *pos;
size_t len;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
+ if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+ &len);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
+ respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
return TRUE;
@@ -178,7 +209,7 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
{
struct eap_tls_data *data = priv;
if (eap_server_tls_process(sm, &data->ssl, respData, data,
- EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
+ data->eap_type, NULL, eap_tls_process_msg) <
0)
eap_tls_state(data, FAILURE);
}
@@ -278,3 +309,34 @@ int eap_server_tls_register(void)
eap_server_method_free(eap);
return ret;
}
+
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+int eap_server_unauth_tls_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS,
+ "UNAUTH-TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_unauth_tls_init;
+ eap->reset = eap_tls_reset;
+ eap->buildReq = eap_tls_buildReq;
+ eap->check = eap_tls_check;
+ eap->process = eap_tls_process;
+ eap->isDone = eap_tls_isDone;
+ eap->getKey = eap_tls_getKey;
+ eap->isSuccess = eap_tls_isSuccess;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
+#endif /* EAP_SERVER_UNAUTH_TLS */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 88a410de..31be2ecb 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -18,6 +18,18 @@
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier)
+{
+ if (type == EAP_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
+ code, identifier);
+ return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+ identifier);
+}
+
+
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer)
{
@@ -131,8 +143,7 @@ struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
plen += 4;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
- EAP_CODE_REQUEST, id);
+ req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
if (req == NULL)
return NULL;
@@ -168,8 +179,7 @@ struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
{
struct wpabuf *req;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
- id);
+ req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
if (req == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "SSL: Building ACK");
@@ -359,7 +369,13 @@ int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
size_t left;
int ret, res = 0;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
+ if (eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+ &left);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
+ &left);
if (pos == NULL || left < 1)
return 0; /* Should not happen - frame already validated */
flags = *pos++;
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index 3d2403e1..67a3dfa3 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -9,7 +9,6 @@
#include "includes.h"
#include "common.h"
-#include "base64.h"
#include "eap_i.h"
#include "tncs.h"
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 45fbf52d..647bd2fa 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -674,6 +674,13 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
return;
}
+ if (sm->identity == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user identity "
+ "known");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
@@ -979,11 +986,12 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
if (parse.user_name) {
os_free(sm->identity);
sm->identity = os_malloc(parse.user_name_len);
- if (sm->identity) {
- os_memcpy(sm->identity, parse.user_name,
- parse.user_name_len);
- sm->identity_len = parse.user_name_len;
+ if (sm->identity == NULL) {
+ eap_ttls_state(data, FAILURE);
+ goto done;
}
+ os_memcpy(sm->identity, parse.user_name, parse.user_name_len);
+ sm->identity_len = parse.user_name_len;
if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1)
!= 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not "
diff --git a/src/eap_server/eap_server_vendor_test.c b/src/eap_server/eap_server_vendor_test.c
index e4c8bc3d..30f600d3 100644
--- a/src/eap_server/eap_server_vendor_test.c
+++ b/src/eap_server/eap_server_vendor_test.c
@@ -12,7 +12,7 @@
#include "eap_i.h"
-#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
#define EAP_VENDOR_TYPE 0xfcfbfaf9
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index ce3238c9..68fb1f0a 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -340,6 +340,7 @@ static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
addr.sun_family = AF_UNIX;
os_snprintf(addr.sun_path, sizeof(addr.sun_path),
"/tmp/eap_sim_db_%d-%d", getpid(), counter++);
+ os_free(data->local_sock);
data->local_sock = os_strdup(addr.sun_path);
if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind(eap_sim_db)");
@@ -407,8 +408,11 @@ void * eap_sim_db_init(const char *config,
goto fail;
if (os_strncmp(data->fname, "unix:", 5) == 0) {
- if (eap_sim_db_open_socket(data))
- goto fail;
+ if (eap_sim_db_open_socket(data)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
+ "connection not available - will retry "
+ "later");
+ }
}
return data;
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 31fe503f..11f58275 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -62,7 +62,12 @@ struct eap_ssl_data {
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer);
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 8d6d18fc..c3ccb46b 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -757,7 +757,8 @@ SM_STEP(CTRL_DIR)
struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
int flags, const struct wpabuf *assoc_wps_ie,
- const struct wpabuf *assoc_p2p_ie, void *sta_ctx)
+ const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
+ const char *identity, const char *radius_cui)
{
struct eapol_state_machine *sm;
struct eap_config eap_conf;
@@ -838,6 +839,15 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
eapol_auth_initialize(sm);
+ if (identity) {
+ sm->identity = (u8 *) os_strdup(identity);
+ if (sm->identity)
+ sm->identity_len = os_strlen(identity);
+ }
+ if (radius_cui)
+ sm->radius_cui = wpabuf_alloc_copy(radius_cui,
+ os_strlen(radius_cui));
+
return sm;
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 5e8ff43d..b50bbdd0 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -77,7 +77,8 @@ void eapol_auth_deinit(struct eapol_authenticator *eapol);
struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
int flags, const struct wpabuf *assoc_wps_ie,
- const struct wpabuf *assoc_p2p_ie, void *sta_ctx);
+ const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
+ const char *identity, const char *radius_cui);
void eapol_auth_free(struct eapol_state_machine *sm);
void eapol_auth_step(struct eapol_state_machine *sm);
void eapol_auth_dump_state(FILE *f, const char *prefix,
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index f0cae700..e3bfa38a 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1,6 +1,6 @@
/*
* EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -139,46 +139,6 @@ struct eapol_sm {
};
-#define IEEE8021X_REPLAY_COUNTER_LEN 8
-#define IEEE8021X_KEY_SIGN_LEN 16
-#define IEEE8021X_KEY_IV_LEN 16
-
-#define IEEE8021X_KEY_INDEX_FLAG 0x80
-#define IEEE8021X_KEY_INDEX_MASK 0x03
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee802_1x_eapol_key {
- u8 type;
- /* Note: key_length is unaligned */
- u8 key_length[2];
- /* does not repeat within the life of the keying material used to
- * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
- u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
- u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
- u8 key_index; /* key flag in the most significant bit:
- * 0 = broadcast (default key),
- * 1 = unicast (key mapping key); key index is in the
- * 7 least significant bits */
- /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
- * the key */
- u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
-
- /* followed by key: if packet body length = 44 + key length, then the
- * key field (of key_length bytes) contains the key in encrypted form;
- * if packet body length = 44, key field is absent and key_length
- * represents the number of least significant octets from
- * MS-MPPE-Send-Key attribute to be used as the keying material;
- * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
static void eapol_sm_txLogoff(struct eapol_sm *sm);
static void eapol_sm_txStart(struct eapol_sm *sm);
static void eapol_sm_processKey(struct eapol_sm *sm);
@@ -664,6 +624,7 @@ struct eap_key_data {
static void eapol_sm_processKey(struct eapol_sm *sm)
{
+#ifndef CONFIG_FIPS
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
struct eap_key_data keydata;
@@ -671,6 +632,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
int key_len, res, sign_key_len, encr_key_len;
u16 rx_key_length;
+ size_t plen;
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
if (sm->last_rx_key == NULL)
@@ -683,9 +645,12 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
return;
}
+ if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
+ return;
hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
- if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
+ plen = be_to_host16(hdr->length);
+ if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
return;
}
@@ -751,7 +716,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
}
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
- key_len = be_to_host16(hdr->length) - sizeof(*key);
+ key_len = plen - sizeof(*key);
if (key_len > 32 || rx_key_length > 32) {
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
key_len ? key_len : rx_key_length);
@@ -822,6 +787,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
}
+#endif /* CONFIG_FIPS */
}
@@ -1778,7 +1744,8 @@ static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
switch (variable) {
case EAPOL_idleWhile:
sm->idleWhile = value;
- eapol_enable_timer_tick(sm);
+ if (sm->idleWhile > 0)
+ eapol_enable_timer_tick(sm);
break;
}
}
@@ -1946,3 +1913,19 @@ void eapol_sm_deinit(struct eapol_sm *sm)
os_free(sm->ctx);
os_free(sm);
}
+
+
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext)
+{
+ if (sm && sm->eap)
+ eap_sm_set_ext_pw_ctx(sm->eap, ext);
+}
+
+
+int eapol_sm_failed(struct eapol_sm *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return !sm->eapSuccess && sm->eapFail;
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 1a20e4b9..d2a4b94a 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -1,6 +1,6 @@
/*
* EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -243,6 +243,7 @@ struct eapol_ctx {
struct eap_peer_config;
+struct ext_password_data;
#ifdef IEEE8021X_EAPOL
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx);
@@ -275,6 +276,9 @@ void eapol_sm_request_reauth(struct eapol_sm *sm);
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm);
void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
const char * eapol_sm_get_method_name(struct eapol_sm *sm);
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext);
+int eapol_sm_failed(struct eapol_sm *sm);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
@@ -366,6 +370,14 @@ static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm)
{
return NULL;
}
+static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext)
+{
+}
+static inline int eapol_sm_failed(struct eapol_sm *sm)
+{
+ return 0;
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SUPP_SM_H */
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index eb2821ea..03380dc6 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -172,6 +172,8 @@ static const char * p2p_state_txt(int state)
return "INVITE_LISTEN";
case P2P_SEARCH_WHEN_READY:
return "SEARCH_WHEN_READY";
+ case P2P_CONTINUE_SEARCH_WHEN_READY:
+ return "CONTINUE_SEARCH_WHEN_READY";
default:
return "?";
}
@@ -725,6 +727,11 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
break;
}
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
if (scan_res) {
p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
msg.group_info, msg.group_info_len);
@@ -782,6 +789,8 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
dev->info.wps_vendor_ext[i] = NULL;
}
+ wpabuf_free(dev->info.wfd_subelems);
+
os_free(dev);
}
@@ -846,6 +855,7 @@ static void p2p_search(struct p2p_data *p2p)
int freq = 0;
enum p2p_scan_type type;
u16 pw_id = DEV_PW_DEFAULT;
+ int res;
if (p2p->drv_in_listen) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
@@ -865,12 +875,18 @@ static void p2p_search(struct p2p_data *p2p)
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
}
- if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
- p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, pw_id)) {
+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
+ p2p->num_req_dev_types, p2p->req_dev_types,
+ p2p->find_dev_id, pw_id);
+ if (res < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Scan request failed");
p2p_continue_find(p2p);
+ } else if (res == 1) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+ "p2p_scan at this point - will try again after "
+ "previous scan completes");
+ p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY);
} else {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
p2p->p2p_scan_running = 1;
@@ -975,7 +991,7 @@ static void p2p_free_req_dev_types(struct p2p_data *p2p)
int p2p_find(struct p2p_data *p2p, 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)
{
int res;
@@ -1009,6 +1025,8 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p->find_type = type;
p2p_device_clear_reported(p2p);
p2p_set_state(p2p, P2P_SEARCH);
+ p2p->search_delay = search_delay;
+ p2p->in_search_delay = 0;
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p->last_p2p_find_timeout = timeout;
if (timeout)
@@ -1070,13 +1088,18 @@ int p2p_search_pending(struct p2p_data *p2p)
int p2p_other_scan_completed(struct p2p_data *p2p)
{
+ if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) {
+ p2p_set_state(p2p, P2P_SEARCH);
+ p2p_search(p2p);
+ return 1;
+ }
if (p2p->state != P2P_SEARCH_WHEN_READY)
return 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
"now that previous scan was completed");
if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id) < 0)
+ p2p->find_dev_id, p2p->search_delay) < 0)
return 0;
return 1;
}
@@ -1442,6 +1465,11 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
}
}
+ if (msg->wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
+ }
+
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1779,6 +1807,11 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
p2p_copy_wps_info(dev, 1, &msg);
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
p2p_parse_free(&msg);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1877,8 +1910,14 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
struct wpabuf *buf;
u8 *len;
int pw_id = -1;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_probe_resp)
+ extra = wpabuf_len(p2p->wfd_ie_probe_resp);
+#endif /* CONFIG_WIFI_DISPLAY */
- buf = wpabuf_alloc(1000);
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -1889,6 +1928,11 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
p2p_build_wps_ie(p2p, buf, pw_id, 1);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_probe_resp)
+ wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
+#endif /* CONFIG_WIFI_DISPLAY */
+
/* P2P IE */
len = p2p_buf_add_ie_hdr(buf);
p2p_buf_add_capability(buf, p2p->dev_capab &
@@ -2173,20 +2217,31 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
struct p2p_device *peer;
size_t tmplen;
int res;
+ size_t extra = 0;
if (!p2p_group)
return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_assoc_req)
+ extra = wpabuf_len(p2p->wfd_ie_assoc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
/*
* (Re)Association Request - P2P IE
* P2P Capability attribute (shall be present)
* Extended Listen Timing (may be present)
* P2P Device Info attribute (shall be present)
*/
- tmp = wpabuf_alloc(200);
+ tmp = wpabuf_alloc(200 + extra);
if (tmp == NULL)
return -1;
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_assoc_req)
+ wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
lpos = p2p_buf_add_ie_hdr(tmp);
@@ -2370,12 +2425,29 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
p2p_expiration_timeout, p2p, NULL);
+ p2p->go_timeout = 100;
+ p2p->client_timeout = 20;
+
return p2p;
}
void p2p_deinit(struct p2p_data *p2p)
{
+#ifdef CONFIG_WIFI_DISPLAY
+ wpabuf_free(p2p->wfd_ie_beacon);
+ wpabuf_free(p2p->wfd_ie_probe_req);
+ wpabuf_free(p2p->wfd_ie_probe_resp);
+ wpabuf_free(p2p->wfd_ie_assoc_req);
+ wpabuf_free(p2p->wfd_ie_invitation);
+ wpabuf_free(p2p->wfd_ie_prov_disc_req);
+ wpabuf_free(p2p->wfd_ie_prov_disc_resp);
+ wpabuf_free(p2p->wfd_ie_go_neg);
+ wpabuf_free(p2p->wfd_dev_info);
+ wpabuf_free(p2p->wfd_assoc_bssid);
+ wpabuf_free(p2p->wfd_coupled_sink_info);
+#endif /* CONFIG_WIFI_DISPLAY */
+
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
@@ -2723,7 +2795,13 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
if (!success) {
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
- if (p2p->state != P2P_IDLE)
+ if (p2p->user_initiated_pd &&
+ (p2p->state == P2P_SEARCH || p2p->state == P2P_LISTEN_ONLY))
+ {
+ /* Retry request from timeout to avoid busy loops */
+ p2p->pending_action_state = P2P_PENDING_PD;
+ p2p_set_timeout(p2p, 0, 50000);
+ } else if (p2p->state != P2P_IDLE)
p2p_continue_find(p2p);
else if (p2p->user_initiated_pd) {
p2p->pending_action_state = P2P_PENDING_PD;
@@ -2775,7 +2853,14 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
- u8 *len = p2p_buf_add_ie_hdr(ies);
+ u8 *len;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_probe_req)
+ wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ len = p2p_buf_add_ie_hdr(ies);
p2p_buf_add_capability(ies, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
if (dev_id)
@@ -2794,7 +2879,14 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
{
- return 100;
+ size_t len = 100;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p && p2p->wfd_ie_probe_req)
+ len += wpabuf_len(p2p->wfd_ie_probe_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ return len;
}
@@ -2845,7 +2937,7 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
* channel.
*/
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, success ? 200000 : 100000);
}
@@ -2861,7 +2953,7 @@ static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success)
return;
}
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, 250000);
}
@@ -3056,6 +3148,14 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
p2p_set_timeout(p2p, 0, 100000);
return 1;
}
+ if (p2p->search_delay) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
+ "search operation by %u ms",
+ p2p->search_delay);
+ p2p_set_timeout(p2p, p2p->search_delay / 1000,
+ (p2p->search_delay % 1000) * 1000);
+ return 1;
+ }
p2p_search(p2p);
return 1;
}
@@ -3250,6 +3350,16 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
/* Check if we timed out waiting for PD req */
if (p2p->pending_action_state == P2P_PENDING_PD)
p2p_timeout_prov_disc_req(p2p);
+ if (p2p->search_delay && !p2p->in_search_delay) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
+ "search operation by %u ms",
+ p2p->search_delay);
+ p2p->in_search_delay = 1;
+ p2p_set_timeout(p2p, p2p->search_delay / 1000,
+ (p2p->search_delay % 1000) * 1000);
+ break;
+ }
+ p2p->in_search_delay = 0;
p2p_search(p2p);
break;
case P2P_CONNECT:
@@ -3295,6 +3405,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
break;
case P2P_SEARCH_WHEN_READY:
break;
+ case P2P_CONTINUE_SEARCH_WHEN_READY:
+ break;
}
}
@@ -3478,6 +3590,24 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
pos += res;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (dev->info.wfd_subelems) {
+ res = os_snprintf(pos, end - pos, "wfd_subelems=");
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(dev->info.wfd_subelems),
+ wpabuf_len(dev->info.wfd_subelems));
+
+ res = os_snprintf(pos, end - pos, "\n");
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return pos - buf;
}
@@ -4085,5 +4215,150 @@ int p2p_in_progress(struct p2p_data *p2p)
{
if (p2p == NULL)
return 0;
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY ||
+ p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY)
+ return 2;
return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
}
+
+
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+ u8 client_timeout)
+{
+ if (p2p) {
+ p2p->go_timeout = go_timeout;
+ p2p->client_timeout = client_timeout;
+ }
+}
+
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
+{
+ if (p2p && p2p->search_delay < delay)
+ p2p->search_delay = delay;
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
+{
+ size_t g;
+ struct p2p_group *group;
+
+ for (g = 0; g < p2p->num_groups; g++) {
+ group = p2p->groups[g];
+ p2p_group_update_ies(group);
+ }
+}
+
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_beacon);
+ p2p->wfd_ie_beacon = ie;
+ p2p_update_wfd_ie_groups(p2p);
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_probe_req);
+ p2p->wfd_ie_probe_req = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_probe_resp);
+ p2p->wfd_ie_probe_resp = ie;
+ p2p_update_wfd_ie_groups(p2p);
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_assoc_req);
+ p2p->wfd_ie_assoc_req = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_invitation);
+ p2p->wfd_ie_invitation = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_prov_disc_req);
+ p2p->wfd_ie_prov_disc_req = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_prov_disc_resp);
+ p2p->wfd_ie_prov_disc_resp = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_go_neg);
+ p2p->wfd_ie_go_neg = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_dev_info);
+ if (elem) {
+ p2p->wfd_dev_info = wpabuf_dup(elem);
+ if (p2p->wfd_dev_info == NULL)
+ return -1;
+ } else
+ p2p->wfd_dev_info = NULL;
+
+ return 0;
+}
+
+
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_assoc_bssid);
+ if (elem) {
+ p2p->wfd_assoc_bssid = wpabuf_dup(elem);
+ if (p2p->wfd_assoc_bssid == NULL)
+ return -1;
+ } else
+ p2p->wfd_assoc_bssid = NULL;
+
+ return 0;
+}
+
+
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+ const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_coupled_sink_info);
+ if (elem) {
+ p2p->wfd_coupled_sink_info = wpabuf_dup(elem);
+ if (p2p->wfd_coupled_sink_info == NULL)
+ return -1;
+ } else
+ p2p->wfd_coupled_sink_info = NULL;
+
+ return 0;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 59da4527..b80f8984 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -79,6 +79,8 @@ struct p2p_go_neg_results {
*/
int freq;
+ int ht40;
+
/**
* ssid - SSID of the group
*/
@@ -214,6 +216,11 @@ struct p2p_peer_info {
size_t wps_sec_dev_type_list_len;
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+ /**
+ * wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
+ */
+ struct wpabuf *wfd_subelems;
};
enum p2p_prov_disc_status {
@@ -841,12 +848,13 @@ enum p2p_discovery_type {
* containing num_req_dev_types * WPS_DEV_TYPE_LEN bytes; %NULL if no
* requested device types.
* @dev_id: Device ID to search for or %NULL to find all devices
+ * @search_delay: Extra delay in milliseconds between search iterations
* Returns: 0 on success, -1 on failure
*/
int p2p_find(struct p2p_data *p2p, 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);
/**
* p2p_stop_find - Stop P2P Find (Device Discovery)
@@ -969,6 +977,11 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
const struct wpabuf *tlvs);
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+ const struct wpabuf *tlvs);
+#endif /* CONFIG_WIFI_DISPLAY */
+
/**
* p2p_sd_cancel_request - Cancel a pending service discovery query
* @p2p: P2P module context from p2p_init()
@@ -1729,4 +1742,29 @@ int p2p_other_scan_completed(struct p2p_data *p2p);
const char * p2p_wps_method_text(enum p2p_wps_method method);
+/**
+ * p2p_set_config_timeout - Set local config timeouts
+ * @p2p: P2P module context from p2p_init()
+ * @go_timeout: Time in 10 ms units it takes to start the GO mode
+ * @client_timeout: Time in 10 ms units it takes to start the client mode
+ */
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+ u8 client_timeout);
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+ const struct wpabuf *elem);
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 248b2a06..031b3a1f 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -134,8 +134,14 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
struct wpabuf *buf;
u8 *len;
u8 group_capab;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -161,7 +167,7 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
p2p->next_tie_breaker);
p2p->next_tie_breaker = !p2p->next_tie_breaker;
- p2p_buf_add_config_timeout(buf, 100, 20);
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
p2p->cfg->channel);
if (p2p->ext_listen_interval)
@@ -177,6 +183,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
/* WPS IE with Device Password ID attribute */
p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
@@ -246,10 +257,17 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
struct wpabuf *buf;
u8 *len;
u8 group_capab;
+ size_t extra = 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Building GO Negotiation Response");
- buf = wpabuf_alloc(1000);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -274,7 +292,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
- p2p_buf_add_config_timeout(buf, 100, 20);
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
if (peer && peer->go_state == REMOTE_GO) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
"Channel attribute");
@@ -308,6 +326,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_wps_method_pw_id(peer ? peer->wps_method :
WPS_NOT_READY), 0);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
return buf;
}
@@ -692,7 +716,7 @@ fail:
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 250) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
}
@@ -710,10 +734,17 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
u8 *len;
struct p2p_channels res;
u8 group_capab;
+ size_t extra = 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Building GO Negotiation Confirm");
- buf = wpabuf_alloc(1000);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -752,6 +783,11 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
}
p2p_buf_update_ie_hdr(buf, len);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 8d4a3cbe..86873205 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -22,6 +22,7 @@ struct p2p_group_member {
u8 addr[ETH_ALEN]; /* P2P Interface Address */
u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
struct wpabuf *p2p_ie;
+ struct wpabuf *wfd_ie;
struct wpabuf *client_info;
u8 dev_capab;
};
@@ -37,12 +38,10 @@ struct p2p_group {
int group_formation;
int beacon_update;
struct wpabuf *noa;
+ struct wpabuf *wfd_ie;
};
-static void p2p_group_update_ies(struct p2p_group *group);
-
-
struct p2p_group * p2p_group_init(struct p2p_data *p2p,
struct p2p_group_config *config)
{
@@ -52,8 +51,8 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p,
if (group == NULL)
return NULL;
- groups = os_realloc(p2p->groups, (p2p->num_groups + 1) *
- sizeof(struct p2p_group *));
+ groups = os_realloc_array(p2p->groups, p2p->num_groups + 1,
+ sizeof(struct p2p_group *));
if (groups == NULL) {
os_free(group);
return NULL;
@@ -74,6 +73,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p,
static void p2p_group_free_member(struct p2p_group_member *m)
{
+ wpabuf_free(m->wfd_ie);
wpabuf_free(m->p2p_ie);
wpabuf_free(m->client_info);
os_free(m);
@@ -118,6 +118,7 @@ void p2p_group_deinit(struct p2p_group *group)
p2p_group_free_members(group);
os_free(group->cfg);
wpabuf_free(group->noa);
+ wpabuf_free(group->wfd_ie);
os_free(group);
}
@@ -172,11 +173,22 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
{
struct wpabuf *ie;
u8 *len;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->p2p->wfd_ie_beacon)
+ extra = wpabuf_len(group->p2p->wfd_ie_beacon);
+#endif /* CONFIG_WIFI_DISPLAY */
- ie = wpabuf_alloc(257);
+ ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->p2p->wfd_ie_beacon)
+ wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
+#endif /* CONFIG_WIFI_DISPLAY */
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
@@ -187,17 +199,193 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
}
+#ifdef CONFIG_WIFI_DISPLAY
+
+struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g)
+{
+ return g->wfd_ie;
+}
+
+
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+
+ if (subelems == NULL)
+ return NULL;
+
+ ie = wpabuf_alloc(wpabuf_len(subelems) + 100);
+ if (ie == NULL)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
+
+
+static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
+ struct p2p_group_member *m)
+{
+ const u8 *pos, *end;
+ const u8 *dev_info = NULL;
+ const u8 *assoc_bssid = NULL;
+ const u8 *coupled_sink = NULL;
+ u8 zero_addr[ETH_ALEN];
+
+ if (m->wfd_ie == NULL)
+ return 0;
+
+ os_memset(zero_addr, 0, ETH_ALEN);
+ pos = wpabuf_head_u8(m->wfd_ie);
+ end = pos + wpabuf_len(m->wfd_ie);
+ while (pos + 1 < end) {
+ u8 id;
+ u16 len;
+
+ id = *pos++;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end)
+ break;
+
+ switch (id) {
+ case WFD_SUBELEM_DEVICE_INFO:
+ if (len < 6)
+ break;
+ dev_info = pos;
+ break;
+ case WFD_SUBELEM_ASSOCIATED_BSSID:
+ if (len < ETH_ALEN)
+ break;
+ assoc_bssid = pos;
+ break;
+ case WFD_SUBELEM_COUPLED_SINK:
+ if (len < 1 + ETH_ALEN)
+ break;
+ coupled_sink = pos;
+ break;
+ }
+
+ pos += len;
+ }
+
+ if (dev_info == NULL)
+ return 0;
+
+ wpabuf_put_u8(buf, 23);
+ wpabuf_put_data(buf, m->dev_addr, ETH_ALEN);
+ if (assoc_bssid)
+ wpabuf_put_data(buf, assoc_bssid, ETH_ALEN);
+ else
+ wpabuf_put_data(buf, zero_addr, ETH_ALEN);
+ wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */
+ wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */
+ if (coupled_sink) {
+ wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN);
+ } else {
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_data(buf, zero_addr, ETH_ALEN);
+ }
+
+ return 1;
+}
+
+
+static struct wpabuf *
+wifi_display_build_go_ie(struct p2p_group *group)
+{
+ struct wpabuf *wfd_subelems, *wfd_ie;
+ struct p2p_group_member *m;
+ u8 *len;
+ unsigned int count = 0;
+
+ if (!group->p2p->wfd_ie_probe_resp)
+ return NULL;
+
+ wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) +
+ group->num_members * 24 + 100);
+ if (wfd_subelems == NULL)
+ return NULL;
+ if (group->p2p->wfd_dev_info)
+ wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
+ if (group->p2p->wfd_assoc_bssid)
+ wpabuf_put_buf(wfd_subelems,
+ group->p2p->wfd_assoc_bssid);
+ if (group->p2p->wfd_coupled_sink_info)
+ wpabuf_put_buf(wfd_subelems,
+ group->p2p->wfd_coupled_sink_info);
+
+ /* Build WFD Session Info */
+ wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO);
+ len = wpabuf_put(wfd_subelems, 2);
+ m = group->members;
+ while (m) {
+ if (wifi_display_add_dev_info_descr(wfd_subelems, m))
+ count++;
+ m = m->next;
+ }
+
+ if (count == 0) {
+ /* No Wi-Fi Display clients - do not include subelement */
+ wfd_subelems->used -= 3;
+ } else {
+ WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
+ 2);
+ wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors",
+ count);
+ }
+
+ wfd_ie = wifi_display_encaps(wfd_subelems);
+ wpabuf_free(wfd_subelems);
+
+ return wfd_ie;
+}
+
+static void wifi_display_group_update(struct p2p_group *group)
+{
+ wpabuf_free(group->wfd_ie);
+ group->wfd_ie = wifi_display_build_go_ie(group);
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
u8 *group_info;
struct wpabuf *ie;
struct p2p_group_member *m;
u8 *len;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ extra += wpabuf_len(group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
- ie = wpabuf_alloc(257);
+ ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ wpabuf_put_buf(ie, group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
@@ -216,15 +404,20 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
(u8 *) wpabuf_put(ie, 0) - group_info - 3);
p2p_buf_update_ie_hdr(ie, len);
+
return ie;
}
-static void p2p_group_update_ies(struct p2p_group *group)
+void p2p_group_update_ies(struct p2p_group *group)
{
struct wpabuf *beacon_ie;
struct wpabuf *probe_resp_ie;
+#ifdef CONFIG_WIFI_DISPLAY
+ wifi_display_group_update(group);
+#endif /* CONFIG_WIFI_DISPLAY */
+
probe_resp_ie = p2p_group_build_probe_resp_ie(group);
if (probe_resp_ie == NULL)
return;
@@ -354,6 +547,9 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
&m->dev_capab,
m->dev_addr);
}
+#ifdef CONFIG_WIFI_DISPLAY
+ m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE);
+#endif /* CONFIG_WIFI_DISPLAY */
p2p_group_remove_member(group, addr);
@@ -361,8 +557,9 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
group->members = m;
group->num_members++;
wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
- " to group (p2p=%d client_info=%d); num_members=%u/%u",
- MAC2STR(addr), m->p2p_ie ? 1 : 0, m->client_info ? 1 : 0,
+ " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
+ MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
+ m->client_info ? 1 : 0,
group->num_members, group->cfg->max_clients);
if (group->num_members == group->cfg->max_clients)
group->beacon_update = 1;
@@ -378,6 +575,12 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
{
struct wpabuf *resp;
u8 *rlen;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ extra = wpabuf_len(group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
/*
* (Re)Association Response - P2P IE
@@ -385,9 +588,15 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
* denied)
* Extended Listen Timing (may be present)
*/
- resp = wpabuf_alloc(20);
+ resp = wpabuf_alloc(20 + extra);
if (resp == NULL)
return NULL;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ wpabuf_put_buf(resp, group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
rlen = p2p_buf_add_ie_hdr(resp);
if (status != P2P_SC_SUCCESS)
p2p_buf_add_status(resp, status);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index b0abff0b..bf550158 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -109,6 +109,7 @@ struct p2p_sd_query {
struct p2p_sd_query *next;
u8 peer[ETH_ALEN];
int for_all_peers;
+ int wsd; /* Wi-Fi Display Service Discovery Request */
struct wpabuf *tlvs;
};
@@ -207,6 +208,11 @@ struct p2p_data {
* P2P_SEARCH_WHEN_READY - Waiting to start Search
*/
P2P_SEARCH_WHEN_READY,
+
+ /**
+ * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search
+ */
+ P2P_CONTINUE_SEARCH_WHEN_READY,
} state;
/**
@@ -437,6 +443,27 @@ struct p2p_data {
* in IDLE state.
*/
int pd_retries;
+
+ u8 go_timeout;
+ u8 client_timeout;
+
+ /* Extra delay in milliseconds between search iterations */
+ unsigned int search_delay;
+ int in_search_delay;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie_beacon;
+ struct wpabuf *wfd_ie_probe_req;
+ struct wpabuf *wfd_ie_probe_resp;
+ struct wpabuf *wfd_ie_assoc_req;
+ struct wpabuf *wfd_ie_invitation;
+ struct wpabuf *wfd_ie_prov_disc_req;
+ struct wpabuf *wfd_ie_prov_disc_resp;
+ struct wpabuf *wfd_ie_go_neg;
+ struct wpabuf *wfd_dev_info;
+ struct wpabuf *wfd_assoc_bssid;
+ struct wpabuf *wfd_coupled_sink_info;
+#endif /* CONFIG_WIFI_DISPLAY */
};
/**
@@ -445,6 +472,7 @@ struct p2p_data {
struct p2p_message {
struct wpabuf *p2p_attributes;
struct wpabuf *wps_attributes;
+ struct wpabuf *wfd_subelems;
u8 dialog_token;
@@ -565,6 +593,8 @@ u8 p2p_group_presence_req(struct p2p_group *group,
const u8 *noa, size_t noa_len);
int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
size_t group_id_len);
+void p2p_group_update_ies(struct p2p_group *group);
+struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 59255495..df24c645 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -21,8 +21,27 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
struct wpabuf *buf;
u8 *len;
const u8 *dev_addr;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
+ if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ struct p2p_group *g = p2p->groups[i];
+ struct wpabuf *ie;
+ ie = p2p_group_get_wfd_ie(g);
+ if (ie) {
+ wfd_ie = ie;
+ break;
+ }
+ }
+ }
+ if (wfd_ie)
+ extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
- buf = wpabuf_alloc(1000);
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -36,7 +55,8 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent)
p2p_buf_add_config_timeout(buf, 0, 0);
else
- p2p_buf_add_config_timeout(buf, 100, 20);
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
P2P_INVITATION_FLAGS_TYPE : 0);
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -54,6 +74,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
p2p_buf_add_device_info(buf, p2p, peer);
p2p_buf_update_ie_hdr(buf, len);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_ie)
+ wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
@@ -67,8 +92,30 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
{
struct wpabuf *buf;
u8 *len;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
+ if (wfd_ie && group_bssid) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ struct p2p_group *g = p2p->groups[i];
+ struct wpabuf *ie;
+ if (!p2p_group_is_group_id_match(g, group_bssid,
+ ETH_ALEN))
+ continue;
+ ie = p2p_group_get_wfd_ie(g);
+ if (ie) {
+ wfd_ie = ie;
+ break;
+ }
+ }
+ }
+ if (wfd_ie)
+ extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
- buf = wpabuf_alloc(1000);
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -87,6 +134,11 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
p2p_buf_update_ie_hdr(buf, len);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_ie)
+ wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index a3ec57df..097a31de 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -414,6 +414,13 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
return -1;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (elems.wfd) {
+ msg->wfd_subelems = ieee802_11_vendor_ie_concat(
+ data, len, WFD_IE_VENDOR_TYPE);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return 0;
}
@@ -453,6 +460,10 @@ void p2p_parse_free(struct p2p_message *msg)
msg->p2p_attributes = NULL;
wpabuf_free(msg->wps_attributes);
msg->wps_attributes = NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ wpabuf_free(msg->wfd_subelems);
+ msg->wfd_subelems = NULL;
+#endif /* CONFIG_WIFI_DISPLAY */
}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 38a9dd81..a2d5aeeb 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -16,8 +16,8 @@
/*
- * Number of retries to attempt for provision discovery requests during IDLE
- * state in case the peer is not listening.
+ * Number of retries to attempt for provision discovery requests
+ * in case the peer is not listening.
*/
#define MAX_PROV_DISC_REQ_RETRIES 10
@@ -46,8 +46,14 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
{
struct wpabuf *buf;
u8 *len;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_prov_disc_req)
+ extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -66,17 +72,46 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
/* WPS IE with Config Methods attribute */
p2p_build_wps_ie_config_methods(buf, config_methods);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_prov_disc_req)
+ wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
u8 dialog_token,
- u16 config_methods)
+ u16 config_methods,
+ const u8 *group_id,
+ size_t group_id_len)
{
struct wpabuf *buf;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
+ if (wfd_ie && group_id) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ struct p2p_group *g = p2p->groups[i];
+ struct wpabuf *ie;
+ if (!p2p_group_is_group_id_match(g, group_id,
+ group_id_len))
+ continue;
+ ie = p2p_group_get_wfd_ie(g);
+ if (ie) {
+ wfd_ie = ie;
+ break;
+ }
+ }
+ }
+ if (wfd_ie)
+ extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
- buf = wpabuf_alloc(100);
+ buf = wpabuf_alloc(100 + extra);
if (buf == NULL)
return NULL;
@@ -85,6 +120,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
/* WPS IE with Config Methods attribute */
p2p_build_wps_ie_config_methods(buf, config_methods);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_ie)
+ wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
@@ -117,6 +157,9 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
"P2P: Provision Discovery Request add device "
"failed " MACSTR, MAC2STR(sa));
}
+ } else if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
if (!(msg.wps_config_methods &
@@ -162,7 +205,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
out:
resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
- reject ? 0 : msg.wps_config_methods);
+ reject ? 0 : msg.wps_config_methods,
+ msg.group_id, msg.group_id_len);
if (resp == NULL) {
p2p_parse_free(&msg);
return;
@@ -408,8 +452,7 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
*/
p2p->user_initiated_pd = !join;
- /* Also set some retries to attempt in case of IDLE state */
- if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+ if (p2p->user_initiated_pd)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 7a59f107..bf756050 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -15,15 +15,55 @@
#include "p2p.h"
+#ifdef CONFIG_WIFI_DISPLAY
+static int wfd_wsd_supported(struct wpabuf *wfd)
+{
+ const u8 *pos, *end;
+ u8 subelem;
+ u16 len;
+
+ if (wfd == NULL)
+ return 0;
+
+ pos = wpabuf_head(wfd);
+ end = pos + wpabuf_len(wfd);
+
+ while (pos + 3 <= end) {
+ subelem = *pos++;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end)
+ break;
+
+ if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
+ u16 info = WPA_GET_BE16(pos);
+ return !!(info & 0x0040);
+ }
+
+ pos += len;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
struct p2p_device *dev)
{
struct p2p_sd_query *q;
+ int wsd = 0;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
return NULL; /* peer does not support SD */
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_wsd_supported(dev->info.wfd_subelems))
+ wsd = 1;
+#endif /* CONFIG_WIFI_DISPLAY */
for (q = p2p->sd_queries; q; q = q->next) {
+ /* Use WSD only if the peer indicates support or it */
+ if (q->wsd && !wsd)
+ continue;
if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
return q;
if (!q->for_all_peers &&
@@ -420,7 +460,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
#endif
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Ignore unexpected GAS Initial Response from "
MACSTR, MAC2STR(sa));
return;
@@ -670,7 +710,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
#endif
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Ignore unexpected GAS Comeback Response from "
MACSTR, MAC2STR(sa));
return;
@@ -907,6 +947,19 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
}
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+ const struct wpabuf *tlvs)
+{
+ struct p2p_sd_query *q;
+ q = p2p_sd_request(p2p, dst, tlvs);
+ if (q)
+ q->wsd = 1;
+ return q;
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
#ifdef ANDROID_P2P
void p2p_sd_service_update(struct p2p_data *p2p, int action)
#else
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 2b9cbcaa..d5edfd8c 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -78,8 +78,8 @@ static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
static int radius_msg_initialize(struct radius_msg *msg)
{
- msg->attr_pos =
- os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
+ msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
+ sizeof(*msg->attr_pos));
if (msg->attr_pos == NULL)
return -1;
@@ -269,7 +269,7 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
printf(" Attribute %d (%s) length=%d\n",
hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
- if (attr == NULL)
+ if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
return;
len = hdr->length - sizeof(struct radius_attr_hdr);
@@ -332,7 +332,7 @@ void radius_msg_dump(struct radius_msg *msg)
printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
msg->hdr->code, radius_code_string(msg->hdr->code),
- msg->hdr->identifier, ntohs(msg->hdr->length));
+ msg->hdr->identifier, be_to_host16(msg->hdr->length));
for (i = 0; i < msg->attr_used; i++) {
struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
@@ -357,11 +357,11 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
"Message-Authenticator");
return -1;
}
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
wpabuf_len(msg->buf), (u8 *) (attr + 1));
} else
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
if (wpabuf_len(msg->buf) > 0xffff) {
wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
@@ -387,7 +387,7 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
printf("WARNING: Could not add Message-Authenticator\n");
return -1;
}
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memcpy(msg->hdr->authenticator, req_authenticator,
sizeof(msg->hdr->authenticator));
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
@@ -430,7 +430,7 @@ int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
return -1;
}
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
wpabuf_len(msg->buf), (u8 *) (attr + 1));
@@ -458,7 +458,7 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
const u8 *addr[2];
size_t len[2];
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
addr[0] = wpabuf_head(msg->buf);
len[0] = wpabuf_len(msg->buf);
@@ -562,8 +562,8 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
size_t *nattr_pos;
int nlen = msg->attr_size * 2;
- nattr_pos = os_realloc(msg->attr_pos,
- nlen * sizeof(*msg->attr_pos));
+ nattr_pos = os_realloc_array(msg->attr_pos, nlen,
+ sizeof(*msg->attr_pos));
if (nattr_pos == NULL)
return -1;
@@ -633,7 +633,7 @@ struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
hdr = (struct radius_hdr *) data;
- msg_len = ntohs(hdr->length);
+ msg_len = be_to_host16(hdr->length);
if (msg_len < sizeof(*hdr) || msg_len > len) {
wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
return NULL;
@@ -707,9 +707,9 @@ int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
}
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
{
- u8 *eap, *pos;
+ struct wpabuf *eap;
size_t len, i;
struct radius_attr_hdr *attr;
@@ -719,30 +719,27 @@ u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
len = 0;
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
- if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
+ if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+ attr->length > sizeof(struct radius_attr_hdr))
len += attr->length - sizeof(struct radius_attr_hdr);
}
if (len == 0)
return NULL;
- eap = os_malloc(len);
+ eap = wpabuf_alloc(len);
if (eap == NULL)
return NULL;
- pos = eap;
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
- if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
+ if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+ attr->length > sizeof(struct radius_attr_hdr)) {
int flen = attr->length - sizeof(*attr);
- os_memcpy(pos, attr + 1, flen);
- pos += flen;
+ wpabuf_put_data(eap, attr + 1, flen);
}
}
- if (eap_len)
- *eap_len = len;
-
return eap;
}
@@ -843,7 +840,7 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
for (i = 0; i < src->attr_used; i++) {
attr = radius_get_attr_hdr(src, i);
- if (attr->type == type) {
+ if (attr->type == type && attr->length >= sizeof(*attr)) {
if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
attr->length - sizeof(*attr)))
return -1;
@@ -900,7 +897,8 @@ static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
u32 vendor_id;
struct radius_attr_vendor *vhdr;
- if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
+ if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
+ attr->length < sizeof(*attr))
continue;
left = attr->length - sizeof(*attr);
@@ -1273,7 +1271,7 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
}
}
- if (!attr)
+ if (!attr || attr->length < sizeof(*attr))
return -1;
dlen = attr->length - sizeof(*attr);
@@ -1298,7 +1296,7 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
}
}
- if (!attr)
+ if (!attr || attr->length < sizeof(*attr))
return -1;
*buf = (u8 *) (attr + 1);
@@ -1349,6 +1347,8 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
+ if (attr->length < sizeof(*attr))
+ return -1;
data = (const u8 *) (attr + 1);
dlen = attr->length - sizeof(*attr);
if (attr->length < 3)
@@ -1534,7 +1534,7 @@ int radius_copy_class(struct radius_class_data *dst,
if (src->attr == NULL)
return 0;
- dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
+ dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
if (dst->attr == NULL)
return -1;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 2d059df1..727640b2 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -18,7 +18,7 @@
struct radius_hdr {
u8 code;
u8 identifier;
- u16 length; /* including this header */
+ be16 length; /* including this header */
u8 authenticator[16];
/* followed by length-20 octets of attributes */
} STRUCT_PACKED;
@@ -213,7 +213,7 @@ struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
size_t data_len);
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len);
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg);
int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
size_t secret_len, struct radius_msg *sent_msg,
int auth);
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 1ee71316..425ad935 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -281,8 +281,8 @@ int radius_client_register(struct radius_client_data *radius,
num = &radius->num_auth_handlers;
}
- newh = os_realloc(*handlers,
- (*num + 1) * sizeof(struct radius_rx_handler));
+ newh = os_realloc_array(*handlers, *num + 1,
+ sizeof(struct radius_rx_handler));
if (newh == NULL)
return -1;
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index 8ecfffc9..bded9651 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -127,8 +127,11 @@ fail:
return NULL;
if (error) {
- radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
- error);
+ if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+ error)) {
+ radius_msg_free(reply);
+ return NULL;
+ }
}
return reply;
@@ -225,7 +228,12 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
break;
/* Unsupported Service */
- radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
+ if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+ 405)) {
+ radius_msg_free(reply);
+ reply = NULL;
+ break;
+ }
break;
default:
wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 123c59b7..5b2d7111 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -689,8 +689,7 @@ static int radius_server_request(struct radius_server_data *data,
const char *from_addr, int from_port,
struct radius_session *force_sess)
{
- u8 *eap = NULL;
- size_t eap_len;
+ struct wpabuf *eap = NULL;
int res, state_included = 0;
u8 statebuf[4];
unsigned int state;
@@ -754,7 +753,7 @@ static int radius_server_request(struct radius_server_data *data,
return -1;
}
- eap = radius_msg_get_eap(msg, &eap_len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
from_addr);
@@ -763,7 +762,7 @@ static int radius_server_request(struct radius_server_data *data,
return -1;
}
- RADIUS_DUMP("Received EAP data", eap, eap_len);
+ RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap));
/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
* RFC3579 Sect. 2.6.2.
@@ -773,10 +772,7 @@ static int radius_server_request(struct radius_server_data *data,
* Or is this already done by the EAP state machine? */
wpabuf_free(sess->eap_if->eapRespData);
- sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len);
- if (sess->eap_if->eapRespData == NULL)
- os_free(eap);
- eap = NULL;
+ sess->eap_if->eapRespData = eap;
sess->eap_if->eapResp = TRUE;
eap_server_sm_step(sess->eap);
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index 3d5aac6b..5e4872e9 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -221,6 +221,9 @@ static int wpa_supplicant_process_smk_m2(
if (cipher & WPA_CIPHER_CCMP) {
wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
cipher = WPA_CIPHER_CCMP;
+ } else if (cipher & WPA_CIPHER_GCMP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+ cipher = WPA_CIPHER_GCMP;
} else if (cipher & WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
cipher = WPA_CIPHER_TKIP;
@@ -269,6 +272,8 @@ static int wpa_supplicant_process_smk_m2(
pos += 2;
if (cipher == WPA_CIPHER_CCMP)
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ else if (cipher == WPA_CIPHER_GCMP)
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
else if (cipher == WPA_CIPHER_TKIP)
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
pos += RSN_SELECTOR_LEN;
@@ -344,7 +349,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
msg->type = EAPOL_KEY_TYPE_RSN;
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -352,7 +357,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
WPA_PUT_BE16(msg->key_info, key_info);
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
WPA_PUT_BE16(msg->key_length, 16);
else
WPA_PUT_BE16(msg->key_length, 32);
@@ -403,7 +408,7 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
msg->type = EAPOL_KEY_TYPE_RSN;
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -412,7 +417,7 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
WPA_PUT_BE16(msg->key_info, key_info);
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
WPA_PUT_BE16(msg->key_length, 16);
else
WPA_PUT_BE16(msg->key_length, 32);
@@ -500,6 +505,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
if (cipher & WPA_CIPHER_CCMP) {
wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
peerkey->cipher = WPA_CIPHER_CCMP;
+ } else if (cipher & WPA_CIPHER_GCMP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+ peerkey->cipher = WPA_CIPHER_GCMP;
} else if (cipher & WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
peerkey->cipher = WPA_CIPHER_TKIP;
@@ -1016,7 +1024,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
return -1;
}
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+ if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1061,6 +1069,11 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
pos += RSN_SELECTOR_LEN;
count++;
}
+ if (sm->allowed_pairwise_cipher & WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ }
if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
pos += RSN_SELECTOR_LEN;
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 2d265d08..9783e7c4 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -197,11 +197,25 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
/* Remove the oldest entry to make room for the new entry */
pos = pmksa->pmksa;
- pmksa->pmksa = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
- "entry (for " MACSTR ") to make room for new one",
- MAC2STR(pos->aa));
- pmksa_cache_free_entry(pmksa, pos, 0);
+
+ if (pos == pmksa->sm->cur_pmksa) {
+ /*
+ * Never remove the current PMKSA cache entry, since
+ * it's in use, and removing it triggers a needless
+ * deauthentication.
+ */
+ pos = pos->next;
+ pmksa->pmksa->next = pos ? pos->next : NULL;
+ } else
+ pmksa->pmksa = pos->next;
+
+ if (pos) {
+ wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
+ "PMKSA cache entry (for " MACSTR ") to "
+ "make room for new one",
+ MAC2STR(pos->aa));
+ pmksa_cache_free_entry(pmksa, pos, 0);
+ }
}
/* Add the new entry; order by expiration time */
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 7159c3ae..bcd59510 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -91,7 +91,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
- else if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+ else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -190,14 +190,17 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
#endif /* CONFIG_IEEE80211R */
}
if (res == 0) {
+ struct rsn_pmksa_cache_entry *sa = NULL;
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
if (sm->proto == WPA_PROTO_RSN &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
- pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len,
- src_addr, sm->own_addr,
- sm->network_ctx, sm->key_mgmt);
+ sa = pmksa_cache_add(sm->pmksa,
+ sm->pmk, pmk_len,
+ src_addr, sm->own_addr,
+ sm->network_ctx,
+ sm->key_mgmt);
}
if (!sm->cur_pmksa && pmkid &&
pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
@@ -207,6 +210,9 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
"PMKID");
abort_cached = 0;
}
+
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to get master session key from "
@@ -350,7 +356,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key,
struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
+ size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
@@ -520,6 +526,11 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
keylen = 16;
rsclen = 6;
break;
+ case WPA_CIPHER_GCMP:
+ alg = WPA_ALG_GCMP;
+ keylen = 16;
+ rsclen = 6;
+ break;
case WPA_CIPHER_TKIP:
alg = WPA_ALG_TKIP;
keylen = 32;
@@ -579,6 +590,14 @@ static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
*key_rsc_len = 6;
*alg = WPA_ALG_CCMP;
break;
+ case WPA_CIPHER_GCMP:
+ if (keylen != 16 || maxkeylen < 16) {
+ ret = -1;
+ break;
+ }
+ *key_rsc_len = 6;
+ *alg = WPA_ALG_GCMP;
+ break;
case WPA_CIPHER_TKIP:
if (keylen != 32 || maxkeylen < 32) {
ret = -1;
@@ -1125,6 +1144,14 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
break;
+ case WPA_CIPHER_GCMP:
+ if (keylen != 16) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid GCMP key length %d (src=" MACSTR
+ ")", keylen, MAC2STR(sm->bssid));
+ goto failed;
+ }
+ break;
case WPA_CIPHER_TKIP:
if (keylen != 32) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1712,6 +1739,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
goto out;
}
+ if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: GCMP is used, but EAPOL-Key "
+ "descriptor version (%d) is not 2", ver);
+ goto out;
+ }
#ifdef CONFIG_PEERKEY
for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
@@ -1851,6 +1885,8 @@ static int wpa_cipher_bits(int cipher)
switch (cipher) {
case WPA_CIPHER_CCMP:
return 128;
+ case WPA_CIPHER_GCMP:
+ return 128;
case WPA_CIPHER_TKIP:
return 256;
case WPA_CIPHER_WEP104:
@@ -1900,6 +1936,8 @@ static u32 wpa_cipher_suite(struct wpa_sm *sm, int cipher)
case WPA_CIPHER_CCMP:
return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+ case WPA_CIPHER_GCMP:
+ return RSN_CIPHER_SUITE_GCMP;
case WPA_CIPHER_TKIP:
return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
@@ -2659,3 +2697,125 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
pmksa_cache_flush(sm->pmksa, network_ctx);
#endif /* CONFIG_NO_WPA2 */
}
+
+
+#ifdef CONFIG_IEEE80211V
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
+{
+ struct wpa_gtk_data gd;
+#ifdef CONFIG_IEEE80211W
+ struct wpa_igtk_kde igd;
+ u16 keyidx;
+#endif /* CONFIG_IEEE80211W */
+ u16 keyinfo;
+ u8 keylen; /* plaintext key len */
+ u8 keydatalen;
+ u8 *key_rsc;
+
+ os_memset(&gd, 0, sizeof(gd));
+#ifdef CONFIG_IEEE80211W
+ os_memset(&igd, 0, sizeof(igd));
+#endif /* CONFIG_IEEE80211W */
+
+ switch (sm->group_cipher) {
+ case WPA_CIPHER_CCMP:
+ keylen = 16;
+ gd.key_rsc_len = 6;
+ gd.alg = WPA_ALG_CCMP;
+ break;
+ case WPA_CIPHER_GCMP:
+ keylen = 16;
+ gd.key_rsc_len = 6;
+ gd.alg = WPA_ALG_GCMP;
+ break;
+ case WPA_CIPHER_TKIP:
+ keylen = 32;
+ gd.key_rsc_len = 6;
+ gd.alg = WPA_ALG_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ keylen = 13;
+ gd.key_rsc_len = 0;
+ gd.alg = WPA_ALG_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ keylen = 5;
+ gd.key_rsc_len = 0;
+ gd.alg = WPA_ALG_WEP;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+ return -1;
+ }
+
+ if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+ key_rsc = buf + 5;
+ keyinfo = WPA_GET_LE16(buf+2);
+ keydatalen = buf[1] - 11 - 8;
+ gd.gtk_len = keylen;
+ if (gd.gtk_len != buf[4]) {
+ wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
+ gd.gtk_len, buf[4]);
+ return -1;
+ }
+ gd.keyidx = keyinfo & 0x03; /* B0 - B1 */
+ gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
+ sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
+
+ if (keydatalen % 8) {
+ wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
+ "%d", keydatalen);
+ return -1;
+ }
+
+ if (aes_unwrap(sm->ptk.kek, keydatalen / 8, buf + 13, gd.gtk))
+ {
+ wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
+ "could not decrypt GTK");
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
+ gd.gtk, gd.gtk_len);
+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+ wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
+ "WNM mode");
+ return -1;
+ }
+#ifdef CONFIG_IEEE80211W
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+ if (buf[1] != 2 + 6 + WPA_IGTK_LEN + 8) {
+ wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
+ "%d", buf[1] - 2 - 6 - 8);
+ return -1;
+ }
+ os_memcpy(igd.keyid, buf + 2, 2);
+ os_memcpy(igd.pn, buf + 4, 6);
+
+ keyidx = WPA_GET_LE16(igd.keyid);
+
+ if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, buf + 10,
+ igd.igtk)) {
+ wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
+ "could not decrypr IGTK");
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
+ igd.igtk, WPA_IGTK_LEN);
+ if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+ keyidx, 0, igd.pn, sizeof(igd.pn),
+ igd.igtk, WPA_IGTK_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
+ "WNM mode");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211W */
+ } else {
+ wpa_printf(MSG_DEBUG, "Unknown element id");
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211V */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index a70b57b8..1077b5a0 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -366,4 +366,8 @@ void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+#ifdef CONFIG_IEEE80211V
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+#endif /* CONFIG_IEEE80211V */
+
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index fec95449..bdf389b1 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -173,6 +173,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
/* Group Suite Selector */
if (sm->group_cipher == WPA_CIPHER_CCMP)
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ else if (sm->group_cipher == WPA_CIPHER_GCMP)
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
else if (sm->group_cipher == WPA_CIPHER_TKIP)
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
else {
@@ -190,6 +192,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
/* Pairwise Suite List */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ else if (sm->pairwise_cipher == WPA_CIPHER_GCMP)
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
else if (sm->pairwise_cipher == WPA_CIPHER_TKIP)
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
else {
@@ -328,6 +332,10 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
alg = WPA_ALG_CCMP;
keylen = 16;
break;
+ case WPA_CIPHER_GCMP:
+ alg = WPA_ALG_GCMP;
+ keylen = 16;
+ break;
case WPA_CIPHER_TKIP:
alg = WPA_ALG_TKIP;
keylen = 32;
@@ -483,7 +491,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
+ ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
bssid, sm->pmk_r1_name,
(u8 *) &sm->ptk, ptk_len, ptk_name);
@@ -577,6 +585,11 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
rsc_len = 6;
alg = WPA_ALG_CCMP;
break;
+ case WPA_CIPHER_GCMP:
+ keylen = 16;
+ rsc_len = 6;
+ alg = WPA_ALG_GCMP;
+ break;
case WPA_CIPHER_TKIP:
keylen = 32;
rsc_len = 6;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 56d564cd..16268d56 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -132,6 +132,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
if (group_cipher == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ } else if (group_cipher == WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
} else if (group_cipher == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
} else if (group_cipher == WPA_CIPHER_WEP104) {
@@ -149,6 +151,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
*pos++ = 0;
if (pairwise_cipher == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ } else if (pairwise_cipher == WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
} else if (pairwise_cipher == WPA_CIPHER_NONE) {
diff --git a/src/utils/common.c b/src/utils/common.c
index 26fea1bf..e6369849 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -344,6 +344,135 @@ TCHAR * wpa_strdup_tchar(const char *str)
#endif /* CONFIG_NATIVE_WINDOWS */
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
+{
+ char *end = txt + maxlen;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (txt + 4 > end)
+ break;
+
+ switch (data[i]) {
+ case '\"':
+ *txt++ = '\\';
+ *txt++ = '\"';
+ break;
+ case '\\':
+ *txt++ = '\\';
+ *txt++ = '\\';
+ break;
+ case '\e':
+ *txt++ = '\\';
+ *txt++ = 'e';
+ break;
+ case '\n':
+ *txt++ = '\\';
+ *txt++ = 'n';
+ break;
+ case '\r':
+ *txt++ = '\\';
+ *txt++ = 'r';
+ break;
+ case '\t':
+ *txt++ = '\\';
+ *txt++ = 't';
+ break;
+ default:
+ if (data[i] >= 32 && data[i] <= 127) {
+ *txt++ = data[i];
+ } else {
+ txt += os_snprintf(txt, end - txt, "\\x%02x",
+ data[i]);
+ }
+ break;
+ }
+ }
+
+ *txt = '\0';
+}
+
+
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
+{
+ const char *pos = str;
+ size_t len = 0;
+ int val;
+
+ while (*pos) {
+ if (len == maxlen)
+ break;
+ switch (*pos) {
+ case '\\':
+ pos++;
+ switch (*pos) {
+ case '\\':
+ buf[len++] = '\\';
+ pos++;
+ break;
+ case '"':
+ buf[len++] = '"';
+ pos++;
+ break;
+ case 'n':
+ buf[len++] = '\n';
+ pos++;
+ break;
+ case 'r':
+ buf[len++] = '\r';
+ pos++;
+ break;
+ case 't':
+ buf[len++] = '\t';
+ pos++;
+ break;
+ case 'e':
+ buf[len++] = '\e';
+ pos++;
+ break;
+ case 'x':
+ pos++;
+ val = hex2byte(pos);
+ if (val < 0) {
+ val = hex2num(*pos);
+ if (val < 0)
+ break;
+ buf[len++] = val;
+ pos++;
+ } else {
+ buf[len++] = val;
+ pos += 2;
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = *pos++ - '0';
+ if (*pos >= '0' && *pos <= '7')
+ val = val * 8 + (*pos++ - '0');
+ if (*pos >= '0' && *pos <= '7')
+ val = val * 8 + (*pos++ - '0');
+ buf[len++] = val;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ buf[len++] = *pos++;
+ break;
+ }
+ }
+
+ return len;
+}
+
+
/**
* wpa_ssid_txt - Convert SSID to a printable string
* @ssid: SSID (32-octet string)
@@ -360,19 +489,14 @@ TCHAR * wpa_strdup_tchar(const char *str)
*/
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
{
- static char ssid_txt[33];
- char *pos;
-
- if (ssid_len > 32)
- ssid_len = 32;
- os_memcpy(ssid_txt, ssid, ssid_len);
- ssid_txt[ssid_len] = '\0';
- for (pos = ssid_txt; *pos != '\0'; pos++) {
-#ifndef WPA_UNICODE_SSID
- if ((u8) *pos < 32 || (u8) *pos >= 127)
- *pos = '_';
-#endif
+ static char ssid_txt[32 * 4 + 1];
+
+ if (ssid == NULL) {
+ ssid_txt[0] = '\0';
+ return ssid_txt;
}
+
+ printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
return ssid_txt;
}
@@ -381,3 +505,108 @@ void * __hide_aliasing_typecast(void *foo)
{
return foo;
}
+
+
+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 if (*value == 'P' && value[1] == '"') {
+ const char *pos;
+ char *tstr, *str;
+ size_t tlen;
+ value += 2;
+ pos = os_strrchr(value, '"');
+ if (pos == NULL || pos[1] != '\0')
+ return NULL;
+ tlen = pos - value;
+ tstr = os_malloc(tlen + 1);
+ if (tstr == NULL)
+ return NULL;
+ os_memcpy(tstr, value, tlen);
+ tstr[tlen] = '\0';
+
+ str = os_malloc(tlen + 1);
+ if (str == NULL) {
+ os_free(tstr);
+ return NULL;
+ }
+
+ *len = printf_decode((u8 *) str, tlen + 1, tstr);
+ os_free(tstr);
+
+ 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;
+ }
+}
+
+
+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;
+}
+
+
+size_t merge_byte_arrays(u8 *res, size_t res_len,
+ const u8 *src1, size_t src1_len,
+ const u8 *src2, size_t src2_len)
+{
+ size_t len = 0;
+
+ os_memset(res, 0, res_len);
+
+ if (src1) {
+ if (src1_len >= res_len) {
+ os_memcpy(res, src1, res_len);
+ return res_len;
+ }
+
+ os_memcpy(res, src1, src1_len);
+ len += src1_len;
+ }
+
+ if (src2) {
+ if (len + src2_len >= res_len) {
+ os_memcpy(res + len, src2, res_len - len);
+ return res_len;
+ }
+
+ os_memcpy(res + len, src2, src2_len);
+ len += src2_len;
+ }
+
+ return len;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 7f115efe..5fc916c0 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -441,8 +441,17 @@ TCHAR * wpa_strdup_tchar(const char *str);
#define wpa_strdup_tchar(s) strdup((s))
#endif /* CONFIG_NATIVE_WINDOWS */
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
+
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
+char * wpa_config_parse_string(const char *value, size_t *len);
+int is_hex(const u8 *data, size_t len);
+size_t merge_byte_arrays(u8 *res, size_t res_len,
+ const u8 *src1, size_t src1_len,
+ const u8 *src2, size_t src2_len);
+
static inline int is_zero_ether_addr(const u8 *a)
{
return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
diff --git a/src/utils/edit.c b/src/utils/edit.c
index 280d2447..b01e08df 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -20,6 +20,7 @@ static int cmdbuf_pos = 0;
static int cmdbuf_len = 0;
static char currbuf[CMD_BUF_LEN];
static int currbuf_valid = 0;
+static const char *ps2 = NULL;
#define HISTORY_MAX 100
@@ -47,7 +48,7 @@ void edit_clear_line(void)
{
int i;
putchar('\r');
- for (i = 0; i < cmdbuf_len + 2; i++)
+ for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++)
putchar(' ');
}
@@ -346,7 +347,7 @@ static void process_cmd(void)
{
if (cmdbuf_len == 0) {
- printf("\n> ");
+ printf("\n%s> ", ps2 ? ps2 : "");
fflush(stdout);
return;
}
@@ -356,7 +357,7 @@ static void process_cmd(void)
cmdbuf_pos = 0;
cmdbuf_len = 0;
edit_cmd_cb(edit_cb_ctx, cmdbuf);
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
}
@@ -1112,7 +1113,7 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
currbuf[0] = '\0';
dl_list_init(&history_list);
@@ -1132,7 +1133,8 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
- printf("> ");
+ ps2 = ps;
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return 0;
@@ -1161,11 +1163,11 @@ void edit_redraw(void)
{
char tmp;
cmdbuf[cmdbuf_len] = '\0';
- printf("\r> %s", cmdbuf);
+ printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
if (cmdbuf_pos != cmdbuf_len) {
tmp = cmdbuf[cmdbuf_pos];
cmdbuf[cmdbuf_pos] = '\0';
- printf("\r> %s", cmdbuf);
+ printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
cmdbuf[cmdbuf_pos] = tmp;
}
fflush(stdout);
diff --git a/src/utils/edit.h b/src/utils/edit.h
index e8d04e7f..ad27f1c7 100644
--- a/src/utils/edit.h
+++ b/src/utils/edit.h
@@ -12,7 +12,7 @@
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file);
+ void *ctx, const char *history_file, const char *ps);
void edit_deinit(const char *history_file,
int (*filter_cb)(void *ctx, const char *cmd));
void edit_clear_line(void);
diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c
index c9ff0e6d..add26fa3 100644
--- a/src/utils/edit_readline.c
+++ b/src/utils/edit_readline.c
@@ -112,7 +112,7 @@ static void readline_cmd_handler(char *cmd)
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
edit_cb_ctx = ctx;
edit_cmd_cb = cmd_cb;
@@ -127,6 +127,17 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+ if (ps) {
+ size_t blen = os_strlen(ps) + 3;
+ char *ps2 = os_malloc(blen);
+ if (ps2) {
+ os_snprintf(ps2, blen, "%s> ", ps);
+ rl_callback_handler_install(ps2, readline_cmd_handler);
+ os_free(ps2);
+ return 0;
+ }
+ }
+
rl_callback_handler_install("> ", readline_cmd_handler);
return 0;
@@ -136,6 +147,9 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void edit_deinit(const char *history_file,
int (*filter_cb)(void *ctx, const char *cmd))
{
+ rl_set_prompt("");
+ rl_replace_line("", 0);
+ rl_redisplay();
rl_callback_handler_remove();
readline_free_completions();
diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c
index 0e3637cb..a095ea6a 100644
--- a/src/utils/edit_simple.c
+++ b/src/utils/edit_simple.c
@@ -16,6 +16,7 @@
#define CMD_BUF_LEN 256
static char cmdbuf[CMD_BUF_LEN];
static int cmdbuf_pos = 0;
+static const char *ps2 = NULL;
static void *edit_cb_ctx;
static void (*edit_cmd_cb)(void *ctx, char *cmd);
@@ -41,7 +42,7 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
cmdbuf[cmdbuf_pos] = '\0';
cmdbuf_pos = 0;
edit_cmd_cb(edit_cb_ctx, cmdbuf);
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return;
}
@@ -57,14 +58,15 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
edit_cb_ctx = ctx;
edit_cmd_cb = cmd_cb;
edit_eof_cb = eof_cb;
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+ ps2 = ps;
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return 0;
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index bb324011..d01ae64f 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -153,8 +153,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
#ifdef CONFIG_ELOOP_POLL
if (new_max_sock >= eloop.max_pollfd_map) {
struct pollfd **nmap;
- nmap = os_realloc(eloop.pollfds_map, sizeof(struct pollfd *) *
- (new_max_sock + 50));
+ nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
+ sizeof(struct pollfd *));
if (nmap == NULL)
return -1;
@@ -165,7 +165,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
if (eloop.count + 1 > eloop.max_poll_fds) {
struct pollfd *n;
int nmax = eloop.count + 1 + 50;
- n = os_realloc(eloop.pollfds, sizeof(struct pollfd) * nmax);
+ n = os_realloc_array(eloop.pollfds, nmax,
+ sizeof(struct pollfd));
if (n == NULL)
return -1;
@@ -175,9 +176,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
#endif /* CONFIG_ELOOP_POLL */
eloop_trace_sock_remove_ref(table);
- tmp = (struct eloop_sock *)
- os_realloc(table->table,
- (table->count + 1) * sizeof(struct eloop_sock));
+ tmp = os_realloc_array(table->table, table->count + 1,
+ sizeof(struct eloop_sock));
if (tmp == NULL)
return -1;
@@ -639,10 +639,8 @@ int eloop_register_signal(int sig, eloop_signal_handler handler,
{
struct eloop_signal *tmp;
- tmp = (struct eloop_signal *)
- os_realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
+ tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+ sizeof(struct eloop_signal));
if (tmp == NULL)
return -1;
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 1cf55799..1fafeb2d 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -98,8 +98,8 @@ static int eloop_prepare_handles(void)
if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
return 0;
- n = os_realloc(eloop.handles,
- eloop.num_handles * 2 * sizeof(eloop.handles[0]));
+ n = os_realloc_array(eloop.handles, eloop.num_handles * 2,
+ sizeof(eloop.handles[0]));
if (n == NULL)
return -1;
eloop.handles = n;
@@ -128,8 +128,8 @@ int eloop_register_read_sock(int sock, eloop_sock_handler handler,
WSACloseEvent(event);
return -1;
}
- tmp = os_realloc(eloop.readers,
- (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+ sizeof(struct eloop_sock));
if (tmp == NULL) {
WSAEventSelect(sock, event, 0);
WSACloseEvent(event);
@@ -191,8 +191,8 @@ int eloop_register_event(void *event, size_t event_size,
if (eloop_prepare_handles())
return -1;
- tmp = os_realloc(eloop.events,
- (eloop.event_count + 1) * sizeof(struct eloop_event));
+ tmp = os_realloc_array(eloop.events, eloop.event_count + 1,
+ sizeof(struct eloop_event));
if (tmp == NULL)
return -1;
@@ -392,9 +392,8 @@ int eloop_register_signal(int sig, eloop_signal_handler handler,
{
struct eloop_signal *tmp;
- tmp = os_realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
+ tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+ sizeof(struct eloop_signal));
if (tmp == NULL)
return -1;
diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
new file mode 100644
index 00000000..06131197
--- /dev/null
+++ b/src/utils/ext_password.c
@@ -0,0 +1,116 @@
+/*
+ * External password backend
+ * 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"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif /* __linux__ */
+
+#include "common.h"
+#include "ext_password_i.h"
+
+
+#ifdef CONFIG_EXT_PASSWORD_TEST
+extern struct ext_password_backend ext_password_test;
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+
+static const struct ext_password_backend *backends[] = {
+#ifdef CONFIG_EXT_PASSWORD_TEST
+ &ext_password_test,
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+ NULL
+};
+
+struct ext_password_data {
+ const struct ext_password_backend *backend;
+ void *priv;
+};
+
+
+struct ext_password_data * ext_password_init(const char *backend,
+ const char *params)
+{
+ struct ext_password_data *data;
+ int i;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ for (i = 0; backends[i]; i++) {
+ if (os_strcmp(backends[i]->name, backend) == 0) {
+ data->backend = backends[i];
+ break;
+ }
+ }
+
+ if (!data->backend) {
+ os_free(data);
+ return NULL;
+ }
+
+ data->priv = data->backend->init(params);
+ if (data->priv == NULL) {
+ os_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+void ext_password_deinit(struct ext_password_data *data)
+{
+ if (data && data->backend && data->priv)
+ data->backend->deinit(data->priv);
+ os_free(data);
+}
+
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+ const char *name)
+{
+ if (data == NULL)
+ return NULL;
+ return data->backend->get(data->priv, name);
+}
+
+
+struct wpabuf * ext_password_alloc(size_t len)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return NULL;
+
+#ifdef __linux__
+ if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s",
+ strerror(errno));
+ }
+#endif /* __linux__ */
+
+ return buf;
+}
+
+
+void ext_password_free(struct wpabuf *pw)
+{
+ if (pw == NULL)
+ return;
+ os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
+#ifdef __linux__
+ if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
+ wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s",
+ strerror(errno));
+ }
+#endif /* __linux__ */
+ wpabuf_free(pw);
+}
diff --git a/src/utils/ext_password.h b/src/utils/ext_password.h
new file mode 100644
index 00000000..e3e46ea0
--- /dev/null
+++ b/src/utils/ext_password.h
@@ -0,0 +1,33 @@
+/*
+ * External password backend
+ * 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.
+ */
+
+#ifndef EXT_PASSWORD_H
+#define EXT_PASSWORD_H
+
+struct ext_password_data;
+
+#ifdef CONFIG_EXT_PASSWORD
+
+struct ext_password_data * ext_password_init(const char *backend,
+ const char *params);
+void ext_password_deinit(struct ext_password_data *data);
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+ const char *name);
+void ext_password_free(struct wpabuf *pw);
+
+#else /* CONFIG_EXT_PASSWORD */
+
+#define ext_password_init(b, p) ((void *) 1)
+#define ext_password_deinit(d) do { } while (0)
+#define ext_password_get(d, n) (NULL)
+#define ext_password_free(p) do { } while (0)
+
+#endif /* CONFIG_EXT_PASSWORD */
+
+#endif /* EXT_PASSWORD_H */
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
new file mode 100644
index 00000000..043e7312
--- /dev/null
+++ b/src/utils/ext_password_i.h
@@ -0,0 +1,23 @@
+/*
+ * External password backend - internal definitions
+ * 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.
+ */
+
+#ifndef EXT_PASSWORD_I_H
+#define EXT_PASSWORD_I_H
+
+#include "ext_password.h"
+
+struct ext_password_backend {
+ const char *name;
+ void * (*init)(const char *params);
+ void (*deinit)(void *ctx);
+ struct wpabuf * (*get)(void *ctx, const char *name);
+};
+
+struct wpabuf * ext_password_alloc(size_t len);
+
+#endif /* EXT_PASSWORD_I_H */
diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c
new file mode 100644
index 00000000..3801bb85
--- /dev/null
+++ b/src/utils/ext_password_test.c
@@ -0,0 +1,90 @@
+/*
+ * External password backend
+ * 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 "common.h"
+#include "ext_password_i.h"
+
+
+struct ext_password_test_data {
+ char *params;
+};
+
+
+static void * ext_password_test_init(const char *params)
+{
+ struct ext_password_test_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ if (params)
+ data->params = os_strdup(params);
+
+ return data;
+}
+
+
+static void ext_password_test_deinit(void *ctx)
+{
+ struct ext_password_test_data *data = ctx;
+
+ os_free(data->params);
+ os_free(data);
+}
+
+
+static struct wpabuf * ext_password_test_get(void *ctx, const char *name)
+{
+ struct ext_password_test_data *data = ctx;
+ char *pos, *pos2;
+ size_t nlen;
+
+ wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s)", name);
+
+ pos = data->params;
+ if (pos == NULL)
+ return NULL;
+ nlen = os_strlen(name);
+
+ while (pos && *pos) {
+ if (os_strncmp(pos, name, nlen) == 0 && pos[nlen] == '=') {
+ struct wpabuf *buf;
+ pos += nlen + 1;
+ pos2 = pos;
+ while (*pos2 != '|' && *pos2 != '\0')
+ pos2++;
+ buf = ext_password_alloc(pos2 - pos);
+ if (buf == NULL)
+ return NULL;
+ wpabuf_put_data(buf, pos, pos2 - pos);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EXT PW TEST: value",
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ return buf;
+ }
+
+ pos = os_strchr(pos + 1, '|');
+ if (pos)
+ pos++;
+ }
+
+ wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s) - not found", name);
+
+ return NULL;
+}
+
+
+const struct ext_password_backend ext_password_test = {
+ .name = "test",
+ .init = ext_password_test_init,
+ .deinit = ext_password_test_deinit,
+ .get = ext_password_test_get,
+};
diff --git a/src/utils/os.h b/src/utils/os.h
index 3058b882..ad208341 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -180,6 +180,25 @@ char * os_readfile(const char *name, size_t *len);
*/
void * os_zalloc(size_t size);
+/**
+ * os_calloc - Allocate and zero memory for an array
+ * @nmemb: Number of members in the array
+ * @size: Number of bytes in each member
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * This function can be used as a wrapper for os_zalloc(nmemb * size) when an
+ * allocation is used for an array. The main benefit over os_zalloc() is in
+ * having an extra check to catch integer overflows in multiplication.
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+static inline void * os_calloc(size_t nmemb, size_t size)
+{
+ if (size && nmemb > (~(size_t) 0) / size)
+ return NULL;
+ return os_zalloc(nmemb * size);
+}
+
/*
* The following functions are wrapper for standard ANSI C or POSIX functions.
@@ -467,6 +486,14 @@ char * os_strdup(const char *s);
#endif /* OS_NO_C_LIB_DEFINES */
+static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
+{
+ if (size && nmemb > (~(size_t) 0) / size)
+ return NULL;
+ return os_realloc(ptr, nmemb * size);
+}
+
+
/**
* os_strlcpy - Copy a string with size bound and NUL-termination
* @dest: Destination
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
index b007e669..b257b365 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -68,12 +68,12 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
if (buf->used + add_len > buf->size) {
unsigned char *nbuf;
- if (buf->ext_data) {
- nbuf = os_realloc(buf->ext_data, buf->used + add_len);
+ if (buf->flags & WPABUF_FLAG_EXT_DATA) {
+ nbuf = os_realloc(buf->buf, buf->used + add_len);
if (nbuf == NULL)
return -1;
os_memset(nbuf + buf->used, 0, add_len);
- buf->ext_data = nbuf;
+ buf->buf = nbuf;
} else {
#ifdef WPA_TRACE
nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
@@ -95,6 +95,7 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
add_len);
#endif /* WPA_TRACE */
+ buf->buf = (u8 *) (buf + 1);
*_buf = buf;
}
buf->size = buf->used + add_len;
@@ -126,6 +127,7 @@ struct wpabuf * wpabuf_alloc(size_t len)
#endif /* WPA_TRACE */
buf->size = len;
+ buf->buf = (u8 *) (buf + 1);
return buf;
}
@@ -148,7 +150,8 @@ struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
buf->size = len;
buf->used = len;
- buf->ext_data = data;
+ buf->buf = data;
+ buf->flags |= WPABUF_FLAG_EXT_DATA;
return buf;
}
@@ -189,12 +192,14 @@ void wpabuf_free(struct wpabuf *buf)
wpa_trace_show("wpabuf_free magic mismatch");
abort();
}
- os_free(buf->ext_data);
+ if (buf->flags & WPABUF_FLAG_EXT_DATA)
+ os_free(buf->buf);
os_free(trace);
#else /* WPA_TRACE */
if (buf == NULL)
return;
- os_free(buf->ext_data);
+ if (buf->flags & WPABUF_FLAG_EXT_DATA)
+ os_free(buf->buf);
os_free(buf);
#endif /* WPA_TRACE */
}
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
index 8c36b402..dbce925c 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,9 @@
#ifndef WPABUF_H
#define WPABUF_H
+/* wpabuf::buf is a pointer to external data */
+#define WPABUF_FLAG_EXT_DATA BIT(0)
+
/*
* Internal data structure for wpabuf. Please do not touch this directly from
* elsewhere. This is only defined in header file to allow inline functions
@@ -17,8 +20,8 @@
struct wpabuf {
size_t size; /* total size of the allocated buffer */
size_t used; /* length of data in the buffer */
- u8 *ext_data; /* pointer to external data; NULL if data follows
- * struct wpabuf */
+ u8 *buf; /* pointer to the head of the buffer */
+ unsigned int flags;
/* optionally followed by the allocated buffer */
};
@@ -72,9 +75,7 @@ static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
*/
static inline const void * wpabuf_head(const struct wpabuf *buf)
{
- if (buf->ext_data)
- return buf->ext_data;
- return buf + 1;
+ return buf->buf;
}
static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
@@ -89,9 +90,7 @@ static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
*/
static inline void * wpabuf_mhead(struct wpabuf *buf)
{
- if (buf->ext_data)
- return buf->ext_data;
- return buf + 1;
+ return buf->buf;
}
static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
@@ -150,7 +149,8 @@ static inline void wpabuf_put_buf(struct wpabuf *dst,
static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
{
- buf->ext_data = (u8 *) data;
+ buf->buf = (u8 *) data;
+ buf->flags = WPABUF_FLAG_EXT_DATA;
buf->size = buf->used = len;
}
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 5453962a..4c2322df 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -287,7 +287,8 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
* @msg: WPS IE contents from Beacon or Probe Response frame
* @addr: MAC address to search for
* @ver1_compat: Whether to use version 1 compatibility mode
- * Returns: 1 if address is authorized, 0 if not
+ * Returns: 2 if the specified address is explicit authorized, 1 if address is
+ * authorized (broadcast), 0 if not
*/
int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
int ver1_compat)
@@ -313,8 +314,9 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
pos = attr.authorized_macs;
for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
- if (os_memcmp(pos, addr, ETH_ALEN) == 0 ||
- os_memcmp(pos, bcast, ETH_ALEN) == 0)
+ if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+ return 2;
+ if (os_memcmp(pos, bcast, ETH_ALEN) == 0)
return 1;
pos += ETH_ALEN;
}
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index da0c101b..389aa84e 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -1150,7 +1150,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
return WPS_FAILURE;
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -1242,14 +1242,14 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
}
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -1289,7 +1289,7 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
}
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
@@ -1300,7 +1300,7 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
attr.enrollee_nonce, WPS_NONCE_LEN);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 44bb0063..53684d69 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -2854,7 +2854,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
if (*attr.msg_type != WPS_M1 &&
(attr.registrar_nonce == NULL ||
os_memcmp(wps->nonce_r, attr.registrar_nonce,
- WPS_NONCE_LEN != 0))) {
+ WPS_NONCE_LEN) != 0)) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
@@ -2950,14 +2950,14 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -3019,14 +3019,14 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -3105,14 +3105,14 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 295a897a..eae00d83 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -72,6 +72,11 @@ ifdef CONFIG_DRIVER_NL80211
INCLUDES += external/libnl-headers
endif
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.c
OBJS += notify.c
OBJS += bss.c
@@ -184,6 +189,11 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_IEEE80211V
+L_CFLAGS += -DCONFIG_IEEE80211V
+OBJS += wnm_sta.c
+endif
+
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
@@ -244,6 +254,17 @@ L_CFLAGS += -DCONFIG_P2P_STRICT
endif
endif
+ifdef CONFIG_WIFI_DISPLAY
+L_CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.c
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.c
+L_CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
OBJS += interworking.c
L_CFLAGS += -DCONFIG_INTERWORKING
@@ -734,6 +755,10 @@ ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+endif
+
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
@@ -746,6 +771,12 @@ L_CFLAGS += -DEAP_SERVER_WSC
OBJS += src/ap/wps_hostapd.c
OBJS += src/eap_server/eap_server_wsc.c
endif
+ifdef CONFIG_INTERWORKING
+OBJS += src/ap/gas_serv.c
+endif
+ifdef CONFIG_HS20
+OBJS += src/ap/hs20.c
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -844,8 +875,10 @@ NEED_DES=y
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += src/eap_peer/eap_tls_common.c
OBJS_h += src/eap_server/eap_server_tls_common.c
+ifndef CONFIG_FIPS
NEED_TLS_PRF=y
endif
+endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
@@ -855,6 +888,11 @@ ifdef CONFIG_TLSV11
L_CFLAGS += -DCONFIG_TLSV11
endif
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
L_CFLAGS += -DEAP_TLS_OPENSSL
@@ -939,6 +977,9 @@ OBJS += src/tls/pkcs8.c
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -1044,8 +1085,12 @@ AESOBJS += src/crypto/aes-encblock.c
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += src/crypto/aes-omac1.c
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += src/crypto/aes-wrap.c
@@ -1065,7 +1110,10 @@ endif
SHA1OBJS =
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
ifdef NEED_FIPS186_2_PRF
@@ -1075,8 +1123,10 @@ endif
ifdef CONFIG_NO_WPA_PASSPHRASE
L_CFLAGS += -DCONFIG_NO_PBKDF2
else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1-pbkdf2.c
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += src/crypto/sha1-tprf.c
endif
@@ -1085,14 +1135,13 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c
endif
endif
-MD5OBJS = src/crypto/md5.c
+ifndef CONFIG_FIPS
+MD5OBJS += src/crypto/md5.c
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += src/crypto/md5-internal.c
endif
-ifdef CONFIG_FIPS
-MD5OBJS += src/crypto/md5-non-fips.c
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1119,10 +1168,16 @@ endif
SHA256OBJS = # none by default
ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += src/crypto/sha256.c
+endif
+SHA256OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += src/crypto/sha256-internal.c
endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += src/crypto/sha256-tlsprf.c
+endif
OBJS += $(SHA256OBJS)
endif
@@ -1162,6 +1217,11 @@ endif
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
endif
@@ -1282,6 +1342,10 @@ L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
endif
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
L_CFLAGS += -DCONFIG_DEBUG_FILE
endif
@@ -1297,6 +1361,7 @@ endif
OBJS += $(SHA1OBJS) $(DESOBJS)
OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
ifdef CONFIG_BGSCAN_SIMPLE
L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1332,8 +1397,19 @@ L_CFLAGS += -DCONFIG_AUTOSCAN
OBJS += autoscan.c
endif
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += src/utils/ext_password_test.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += src/utils/ext_password.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
ifdef NEED_GAS
-OBJS += ../src/common/gas.c
+OBJS += src/common/gas.c
OBJS += gas_query.c
L_CFLAGS += -DCONFIG_GAS
NEED_OFFCHANNEL=y
@@ -1371,6 +1447,9 @@ OBJS_priv += src/utils/common.c
OBJS_priv += src/utils/wpa_debug.c
OBJS_priv += src/utils/wpabuf.c
OBJS_priv += wpa_priv.c
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += src/common/ieee802_11_common.c
+endif
ifdef CONFIG_DRIVER_TEST
OBJS_priv += $(SHA1OBJS)
OBJS_priv += $(MD5OBJS)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 6756e54e..227fb4fd 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -55,6 +55,11 @@ $(DESTDIR)$(BINDIR)/%: %
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
$(MAKE) -C ../src install
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.o
OBJS += notify.o
OBJS += bss.o
@@ -167,6 +172,11 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_IEEE80211V
+CFLAGS += -DCONFIG_IEEE80211V
+OBJS += wnm_sta.o
+endif
+
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
@@ -227,6 +237,11 @@ CFLAGS += -DCONFIG_P2P_STRICT
endif
endif
+ifdef CONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.o
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
@@ -296,6 +311,17 @@ TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+OBJS_h += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -741,6 +767,9 @@ endif
ifdef CONFIG_INTERWORKING
OBJS += ../src/ap/gas_serv.o
endif
+ifdef CONFIG_HS20
+OBJS += ../src/ap/hs20.o
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -839,8 +868,10 @@ NEED_DES=y
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += ../src/eap_peer/eap_tls_common.o
OBJS_h += ../src/eap_server/eap_server_tls_common.o
+ifndef CONFIG_FIPS
NEED_TLS_PRF=y
endif
+endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
@@ -868,6 +899,10 @@ OBJS += ../src/crypto/fips_prf_openssl.o
endif
LIBS += -lcrypto
LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
@@ -1047,8 +1082,12 @@ AESOBJS += ../src/crypto/aes-encblock.o
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += ../src/crypto/aes-omac1.o
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-wrap.o
@@ -1067,7 +1106,10 @@ OBJS += $(AESOBJS)
endif
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
@@ -1077,8 +1119,10 @@ endif
ifdef CONFIG_NO_WPA_PASSPHRASE
CFLAGS += -DCONFIG_NO_PBKDF2
else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -1087,14 +1131,13 @@ SHA1OBJS += ../src/crypto/sha1-tlsprf.o
endif
endif
-MD5OBJS = ../src/crypto/md5.o
+ifndef CONFIG_FIPS
+MD5OBJS += ../src/crypto/md5.o
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += ../src/crypto/md5-internal.o
endif
-ifdef CONFIG_FIPS
-MD5OBJS += ../src/crypto/md5-non-fips.o
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1121,7 +1164,10 @@ endif
SHA256OBJS = # none by default
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += ../src/crypto/sha256.o
+endif
+SHA256OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += ../src/crypto/sha256-internal.o
endif
@@ -1167,6 +1213,11 @@ endif
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
endif
@@ -1297,6 +1348,9 @@ endif
ifdef CONFIG_FIPS
CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
endif
OBJS += $(SHA1OBJS) $(DESOBJS)
@@ -1338,6 +1392,17 @@ CFLAGS += -DCONFIG_AUTOSCAN
OBJS += autoscan.o
endif
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
ifdef NEED_GAS
OBJS += ../src/common/gas.o
OBJS += gas_query.o
@@ -1559,6 +1624,11 @@ test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
tests: test-eap_sim_common
+FIPSDIR=/usr/local/ssl/fips-2.0
+FIPSLD=$(FIPSDIR)/bin/fipsld
+fips:
+ $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
+
clean:
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
new file mode 100644
index 00000000..feb90490
--- /dev/null
+++ b/wpa_supplicant/README-HS20
@@ -0,0 +1,470 @@
+wpa_supplicant and Hotspot 2.0
+==============================
+
+This document describe how the IEEE 802.11u Interworking and Wi-Fi
+Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be
+configured and how an external component on the client e.g., management
+GUI or Wi-Fi framework) is used to manage this functionality.
+
+
+Introduction to Wi-Fi Hotspot 2.0
+---------------------------------
+
+Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used
+in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about
+this is available in this white paper:
+
+http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless
+
+The Hotspot 2.0 specification is also available from WFA:
+https://www.wi-fi.org/knowledge-center/published-specifications
+
+The core Interworking functionality (network selection, GAS/ANQP) were
+standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std
+802.11-2012.
+
+
+wpa_supplicant network selection
+--------------------------------
+
+Interworking support added option for configuring credentials that can
+work with multiple networks as an alternative to configuration of
+network blocks (e.g., per-SSID parameters). When requested to perform
+network selection, wpa_supplicant picks the highest priority enabled
+network block or credential. If a credential is picked (based on ANQP
+information from APs), a temporary network block is created
+automatically for the matching network. This temporary network block is
+used similarly to the network blocks that can be configured by the user,
+but it is not stored into the configuration file and is meant to be used
+only for temporary period of time since a new one can be created
+whenever needed based on ANQP information and the credential.
+
+By default, wpa_supplicant is not using automatic network selection
+unless requested explicitly with the interworking_select command. This
+can be changed with the auto_interworking=1 parameter to perform network
+selection automatically whenever trying to find a network for connection
+and none of the enabled network blocks match with the scan results. This
+case works similarly to "interworking_select auto", i.e., wpa_supplicant
+will internally determine which network or credential is going to be
+used based on configured priorities, scan results, and ANQP information.
+
+
+wpa_supplicant configuration
+----------------------------
+
+Interworking and Hotspot 2.0 functionality are optional components that
+need to be enabled in the wpa_supplicant build configuration
+(.config). This is done by adding following parameters into that file:
+
+CONFIG_INTERWORKING=y
+CONFIG_HS20=y
+
+It should be noted that this functionality requires a driver that
+supports GAS/ANQP operations. This uses the same design as P2P, i.e.,
+Action frame processing and building in user space within
+wpa_supplicant. The Linux nl80211 driver interface provides the needed
+functionality for this.
+
+
+There are number of run-time configuration parameters (e.g., in
+wpa_supplicant.conf when using the configuration file) that can be used
+to control Hotspot 2.0 operations.
+
+# Enable Interworking
+interworking=1
+
+# Enable Hotspot 2.0
+hs20=1
+
+# Parameters for controlling scanning
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+#hessid=00:11:22:33:44:55
+
+# Access Network Type
+# When Interworking is enabled, scans can be limited to APs that advertise the
+# specified Access Network Type (0..15; with 15 indicating wildcard match).
+# This value controls the Access Network Type value in Probe Request frames.
+#access_network_type=15
+
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
+
+
+Credentials can be pre-configured for automatic network selection:
+
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# priority: Priority group
+# By default, all networks and credentials get the same priority group
+# (0). This field can be used to give higher priority for credentials
+# (and similarly in struct wpa_ssid for network blocks) to change the
+# Interworking automatic networking selection behavior. The matching
+# network (based on either an enabled network block or a credential)
+# with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+# This field is used with Interworking networking selection for a case
+# where client certificate/private key is used for authentication
+# (EAP-TLS). Full path to the file should be used since working
+# directory may change when wpa_supplicant is run in the background.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key: File path to client private key file (PEM/DER/PFX)
+# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+# commented out. Both the private key and certificate will be read
+# from the PKCS#12 file in this case. Full path to the file should be
+# used since working directory may change when wpa_supplicant is run
+# in the background.
+#
+# Windows certificate store can be used by leaving client_cert out and
+# configuring private_key in one of the following formats:
+#
+# cert://substring_to_match
+#
+# hash://certificate_thumbprint_in_hex
+#
+# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#
+# Note that when running wpa_supplicant as an application, the user
+# certificate store (My user account) is used, whereas computer store
+# (Computer account) is used when running wpasvc as a service.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+# format
+#
+# domain: Home service provider FQDN
+# This is used to compare against the Domain Name List to figure out
+# whether the AP is operated by the Home SP.
+#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# for example:
+#
+#cred={
+# realm="example.com"
+# username="user@example.com"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+#}
+#
+#cred={
+# imsi="310026-000000000"
+# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
+
+
+Control interface
+-----------------
+
+wpa_supplicant provides a control interface that can be used from
+external programs to manage various operations. The included command
+line tool, wpa_cli, can be used for manual testing with this interface.
+
+Following wpa_cli interactive mode commands show some examples of manual
+operations related to Hotspot 2.0:
+
+Remove configured networks and credentials:
+
+> remove_network all
+OK
+> remove_cred all
+OK
+
+
+Add a username/password credential:
+
+> add_cred
+0
+> set_cred 0 realm "mail.example.com"
+OK
+> set_cred 0 username "username"
+OK
+> set_cred 0 password "password"
+OK
+> set_cred 0 priority 1
+OK
+
+Add a SIM credential using a simulated SIM/USIM card for testing:
+
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123"
+OK
+> set_cred 1 priority 1
+OK
+
+Note: the return value of add_cred is used as the first argument to
+the following set_cred commands.
+
+
+Add a WPA2-Enterprise network:
+
+> add_network
+0
+> set_network 0 key_mgmt WPA-EAP
+OK
+> set_network 0 ssid "enterprise"
+OK
+> set_network 0 eap TTLS
+OK
+> set_network 0 anonymous_identity "anonymous"
+OK
+> set_network 0 identity "user"
+OK
+> set_network 0 password "password"
+OK
+> set_network 0 priority 0
+OK
+> enable_network 0 no-connect
+OK
+
+
+Add an open network:
+
+> add_network
+3
+> set_network 3 key_mgmt NONE
+OK
+> set_network 3 ssid "coffee-shop"
+OK
+> select_network 3
+OK
+
+Note: the return value of add_network is used as the first argument to
+the following set_network commands.
+
+The preferred credentials/networks can be indicated with the priority
+parameter (1 is higher priority than 0).
+
+
+Interworking network selection can be started with interworking_select
+command. This instructs wpa_supplicant to run a network scan and iterate
+through the discovered APs to request ANQP information from the APs that
+advertise support for Interworking/Hotspot 2.0:
+
+> interworking_select
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+
+
+INTERWORKING-AP event messages indicate the APs that support network
+selection and for which there is a matching
+credential. interworking_connect command can be used to select a network
+to connect with:
+
+
+> interworking_connect 02:00:00:00:01:00
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=]
+
+
+wpa_supplicant creates a temporary network block for the selected
+network based on the configured credential and ANQP information from the
+AP:
+
+> list_networks
+network id / ssid / bssid / flags
+0 Example Network any [CURRENT]
+> get_network 0 key_mgmt
+WPA-EAP
+> get_network 0 eap
+TTLS
+
+
+Alternatively to using an external program to select the network,
+"interworking_select auto" command can be used to request wpa_supplicant
+to select which network to use based on configured priorities:
+
+
+> remove_network all
+OK
+<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1
+> interworking_select auto
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=]
+
+
+The connection status can be shown with the status command:
+
+> status
+bssid=02:00:00:00:01:00
+ssid=Example Network
+id=0
+mode=station
+pairwise_cipher=CCMP <--- link layer security indication
+group_cipher=CCMP
+key_mgmt=WPA2/IEEE 802.1X/EAP
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+hs20=1 <--- HS 2.0 indication
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+selectedMethod=21 (EAP-TTLS)
+EAP TLS cipher=AES-128-SHA
+EAP-TTLSv0 Phase2 method=PAP
+
+
+> status
+bssid=02:00:00:00:02:00
+ssid=coffee-shop
+id=3
+mode=station
+pairwise_cipher=NONE
+group_cipher=NONE
+key_mgmt=NONE
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+
+
+Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status
+command output. Link layer security is indicated with the
+pairwise_cipher (CCMP = secure, NONE = no encryption used).
+
+
+Also the scan results include the Hotspot 2.0 indication:
+
+> scan_results
+bssid / frequency / signal level / flags / ssid
+02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network
+
+
+ANQP information for the BSS can be fetched using the BSS command:
+
+> bss 02:00:00:00:01:00
+id=1
+bssid=02:00:00:00:01:00
+freq=2412
+beacon_int=100
+capabilities=0x0411
+qual=0
+noise=-92
+level=-30
+tsf=1345573286517276
+age=105
+ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000
+flags=[WPA2-EAP-CCMP][ESS][HS20]
+ssid=Example Network
+anqp_roaming_consortium=031122330510203040500601020304050603fedcba
+
+
+ANQP queries can also be requested with the anqp_get and hs20_anqp_get
+commands:
+
+> anqp_get 02:00:00:00:01:00 261
+OK
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+> hs20_anqp_get 02:00:00:00:01:00 2
+OK
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+
+In addition, fetch_anqp command can be used to request similar set of
+ANQP queries to be done as is run as part of interworking_select:
+
+> scan
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+> fetch_anqp
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index bb4c2ade..6b81397f 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -71,7 +71,8 @@ over the main control interface.
Device Discovery
-p2p_find [timeout in seconds] [type=<social|progressive>]
+p2p_find [timeout in seconds] [type=<social|progressive>] \
+ [dev_id=<addr>] [delay=<search delay in ms>]
The default behavior is to run a single full scan in the beginning and
then scan only social channels. type=social will scan only social
@@ -81,6 +82,11 @@ progressively one channel at the time in the Search state rounds. This
will help in finding new groups or groups missed during the initial
full scan.
+The optional dev_id option can be used to specify a single P2P peer to
+search for. The optional delay parameter can be used to request an extra
+delay to be used between search iterations (e.g., to free up radio
+resources for concurrent operations).
+
p2p_listen [timeout in seconds]
Start Listen-only state (become discoverable without searching for
@@ -250,6 +256,14 @@ p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:Content
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+# Wi-Fi Display examples
+# format: wifi-display <list of roles> <list of subelements>
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
+p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
+
p2p_serv_disc_cancel_req <query identifier>
Cancel a pending P2P service discovery request. This command takes a
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index fc0614d3..d71d1d3a 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -495,3 +495,6 @@ CONFIG_NO_ROAMING=y
# Enable P2P
CONFIG_P2P=y
CONFIG_AP=y
+
+#Enable Wifi Display
+CONFIG_WIFI_DISPLAY=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f9e00457..3798f5a6 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -99,6 +99,18 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
if (!no_ht && mode && mode->ht_capab) {
conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ ssid->ht40)
+ conf->secondary_channel =
+ wpas_p2p_get_ht40_mode(wpa_s, mode,
+ conf->channel);
+ if (conf->secondary_channel)
+ conf->ht_capab |=
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif /* CONFIG_P2P */
/*
* white-list capabilities that won't cause issues
@@ -150,7 +162,6 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
return -1;
}
os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
- bss->ssid.ssid[ssid->ssid_len] = '\0';
bss->ssid.ssid_len = ssid->ssid_len;
bss->ssid.ssid_set = 1;
@@ -207,6 +218,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
if (pairwise & WPA_CIPHER_TKIP)
bss->wpa_group = WPA_CIPHER_TKIP;
+ else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+ WPA_CIPHER_GCMP)
+ bss->wpa_group = WPA_CIPHER_GCMP;
else
bss->wpa_group = WPA_CIPHER_CCMP;
@@ -450,6 +464,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
+ else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP)
+ wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
@@ -491,6 +507,10 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
}
+ os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
+ wpa_s->conf->wmm_ac_params,
+ sizeof(wpa_s->conf->wmm_ac_params));
+
if (params.uapsd > 0) {
conf->bss->wmm_enabled = 1;
conf->bss->wmm_uapsd = 1;
@@ -511,7 +531,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_P2P */
hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL) {
wpa_supplicant_ap_deinit(wpa_s);
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index ed4d879f..adf82d87 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -75,7 +75,7 @@ static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
return;
- n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN);
+ n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
if (n == NULL)
return;
@@ -219,7 +219,7 @@ static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
if (in_array(freqs, bss->freq))
continue;
- n = os_realloc(freqs, (*count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, *count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
@@ -248,7 +248,7 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
"%u", data->supp_freqs[idx]);
data->probe_idx = idx;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
@@ -360,7 +360,7 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
for (j = 0; j < modes[i].num_channels; j++) {
if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
continue;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b89732dd..be210297 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -53,42 +53,6 @@ struct parse_data {
};
-static char * wpa_config_parse_string(const char *value, size_t *len)
-{
- if (*value == '"') {
- const char *pos;
- char *str;
- value++;
- pos = os_strrchr(value, '"');
- if (pos == NULL || pos[1] != '\0')
- return NULL;
- *len = pos - value;
- str = os_malloc(*len + 1);
- if (str == NULL)
- return NULL;
- os_memcpy(str, value, *len);
- str[*len] = '\0';
- return str;
- } else {
- u8 *str;
- size_t tlen, hlen = os_strlen(value);
- if (hlen & 1)
- return NULL;
- tlen = hlen / 2;
- str = os_malloc(tlen + 1);
- if (str == NULL)
- return NULL;
- if (hexstr2bin(value, str, tlen)) {
- os_free(str);
- return NULL;
- }
- str[tlen] = '\0';
- *len = tlen;
- return (char *) str;
- }
-}
-
-
static int wpa_config_parse_str(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
@@ -149,18 +113,6 @@ set:
#ifndef NO_CONFIG_WRITE
-static int is_hex(const u8 *data, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (data[i] < 32 || data[i] >= 127)
- return 1;
- }
- return 0;
-}
-
-
static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
{
char *buf;
@@ -219,26 +171,6 @@ static char * wpa_config_write_str(const struct parse_data *data,
return wpa_config_write_string((const u8 *) *src, len);
}
-
-#ifdef WPA_UNICODE_SSID
-static char * wpa_config_write_str_unicode(const struct parse_data *data,
- struct wpa_ssid *ssid)
-{
- size_t len;
- char **src;
-
- src = (char **) (((u8 *) ssid) + (long) data->param1);
- if (*src == NULL)
- return NULL;
-
- if (data->param2)
- len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
- else
- len = os_strlen(*src);
-
- return wpa_config_write_string_ascii((const u8 *) *src, len);
-}
-#endif
#endif /* NO_CONFIG_WRITE */
@@ -344,6 +276,21 @@ static int wpa_config_parse_psk(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ os_free(ssid->passphrase);
+ ssid->passphrase = NULL;
+ ssid->psk_set = 0;
+ os_free(ssid->ext_psk);
+ ssid->ext_psk = os_strdup(value + 4);
+ if (ssid->ext_psk == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+ ssid->ext_psk);
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (*value == '"') {
#ifndef CONFIG_NO_PBKDF2
const char *pos;
@@ -401,6 +348,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
static char * wpa_config_write_psk(const struct parse_data *data,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+ char *buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (ssid->passphrase)
return wpa_config_write_string_ascii(
(const u8 *) ssid->passphrase,
@@ -685,6 +643,8 @@ static int wpa_config_parse_cipher(int line, const char *value)
*end = '\0';
if (os_strcmp(start, "CCMP") == 0)
val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
else if (os_strcmp(start, "WEP104") == 0)
@@ -736,6 +696,16 @@ static char * wpa_config_write_cipher(int cipher)
pos += ret;
}
+ if (cipher & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+
if (cipher & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP",
pos == buf ? "" : " ");
@@ -789,7 +759,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_NONE)) {
wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
"(0x%x).", line, val);
return -1;
@@ -818,8 +789,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
- WPA_CIPHER_WEP40)) {
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
"(0x%x).", line, val);
return -1;
@@ -949,7 +920,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
used = 0;
len = 10;
- freqs = os_zalloc((len + 1) * sizeof(int));
+ freqs = os_calloc(len + 1, sizeof(int));
if (freqs == NULL)
return NULL;
@@ -960,7 +931,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
if (used == len) {
int *n;
size_t i;
- n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
+ n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
if (n == NULL) {
os_free(freqs);
return NULL;
@@ -1089,8 +1060,8 @@ static int wpa_config_parse_eap(const struct parse_data *data,
last = *end == '\0';
*end = '\0';
tmp = methods;
- methods = os_realloc(methods,
- (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1,
+ sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
os_free(buf);
@@ -1120,7 +1091,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
os_free(buf);
tmp = methods;
- methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
return -1;
@@ -1186,6 +1157,20 @@ static int wpa_config_parse_password(const struct parse_data *data,
return 0;
}
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+ if (name == NULL)
+ return -1;
+ os_free(ssid->eap.password);
+ ssid->eap.password = (u8 *) name;
+ ssid->eap.password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (os_strncmp(value, "hash:", 5) != 0) {
char *tmp;
size_t res_len;
@@ -1203,6 +1188,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
ssid->eap.password = (u8 *) tmp;
ssid->eap.password_len = res_len;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1231,6 +1217,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
ssid->eap.password = hash;
ssid->eap.password_len = 16;
ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1244,6 +1231,17 @@ static char * wpa_config_write_password(const struct parse_data *data,
if (ssid->eap.password == NULL)
return NULL;
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.password_len + 1);
+ if (buf == NULL)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
return wpa_config_write_string(
ssid->eap.password, ssid->eap.password_len);
@@ -1391,18 +1389,27 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
pos++;
if (hwaddr_aton(pos, addr)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "p2p_client_list address '%s'.",
- line, value);
- /* continue anyway */
+ if (count == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "p2p_client_list address '%s'.",
+ line, value);
+ os_free(buf);
+ return -1;
+ }
+ /* continue anyway since this could have been from a
+ * truncated configuration file line */
+ wpa_printf(MSG_INFO, "Line %d: Ignore likely "
+ "truncated p2p_client_list address '%s'",
+ line, pos);
} else {
- n = os_realloc(buf, (count + 1) * ETH_ALEN);
+ n = os_realloc_array(buf, count + 1, ETH_ALEN);
if (n == NULL) {
os_free(buf);
return -1;
}
buf = n;
- os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN);
+ os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
+ os_memcpy(buf, addr, ETH_ALEN);
count++;
wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
addr, ETH_ALEN);
@@ -1436,10 +1443,10 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
pos = value;
end = value + 20 * ssid->num_p2p_clients;
- for (i = 0; i < ssid->num_p2p_clients; i++) {
+ for (i = ssid->num_p2p_clients; i > 0; i--) {
res = os_snprintf(pos, end - pos, MACSTR " ",
MAC2STR(ssid->p2p_client_list +
- i * ETH_ALEN));
+ (i - 1) * ETH_ALEN));
if (res < 0 || res >= end - pos) {
os_free(value);
return NULL;
@@ -1500,15 +1507,6 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
OFFSET(f), (void *) 0
#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
OFFSET(eap.f), (void *) 0
-#ifdef WPA_UNICODE_SSID
-/* STR_* variants that do not force conversion to ASCII */
-#define _STR_UNICODE(f) #f, wpa_config_parse_str, wpa_config_write_str_unicode, OFFSET(f)
-#define STR_UNICODE(f) _STR_UNICODE(f), NULL, NULL, NULL, 0
-#define _STR_LEN_UNICODE(f) _STR_UNICODE(f), OFFSET(f ## _len)
-#define STR_LEN_UNICODE(f) _STR_LEN_UNICODE(f), NULL, NULL, 0
-#define _STR_RANGE_UNICODE(f, min, max) _STR_LEN_UNICODE(f), (void *) (min), (void *) (max)
-#define STR_RANGE_UNICODE(f, min, max) _STR_RANGE_UNICODE(f, min, max), 0
-#endif
#endif /* NO_CONFIG_WRITE */
/* INT: Define an integer variable */
@@ -1553,11 +1551,7 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
* functions.
*/
static const struct parse_data ssid_fields[] = {
-#ifdef WPA_UNICODE_SSID
- { STR_RANGE_UNICODE(ssid, 0, MAX_SSID_LEN) },
-#else
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
-#endif
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
{ FUNC_KEY(psk) },
@@ -1646,15 +1640,6 @@ static const struct parse_data ssid_fields[] = {
{ INT(dtim_period) },
};
-#ifdef WPA_UNICODE_SSID
-#undef _STR_UNICODE
-#undef STR_UNICODE
-#undef _STR_LEN_UNICODE
-#undef STR_LEN_UNICODE
-#undef _STR_RANGE_UNICODE
-#undef STR_RANGE_UNICODE
-#endif
-
#undef OFFSET
#undef _STR
#undef STR
@@ -1706,8 +1691,8 @@ int wpa_config_add_prio_network(struct wpa_config *config,
}
/* First network for this priority - add a new priority list */
- nlist = os_realloc(config->pssid,
- (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ nlist = os_realloc_array(config->pssid, config->num_prio + 1,
+ sizeof(struct wpa_ssid *));
if (nlist == NULL)
return -1;
@@ -1813,6 +1798,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
{
os_free(ssid->ssid);
os_free(ssid->passphrase);
+ os_free(ssid->ext_psk);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
#endif /* IEEE8021X_EAPOL */
@@ -1840,6 +1826,9 @@ void wpa_config_free_cred(struct wpa_cred *cred)
os_free(cred->imsi);
os_free(cred->milenage);
os_free(cred->domain);
+ os_free(cred->eap_method);
+ os_free(cred->phase1);
+ os_free(cred->phase2);
os_free(cred);
}
@@ -1905,6 +1894,7 @@ void wpa_config_free(struct wpa_config *config)
wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
+ os_free(config->ext_password_backend);
os_free(config);
}
@@ -2139,7 +2129,7 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
get_keys = get_keys && ssid->export_keys;
- props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
+ props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
if (!props)
return NULL;
@@ -2267,8 +2257,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
void wpa_config_update_psk(struct wpa_ssid *ssid)
{
#ifndef CONFIG_NO_PBKDF2
- pbkdf2_sha1(ssid->passphrase,
- (char *) ssid->ssid, ssid->ssid_len, 4096,
+ pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
ssid->psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
ssid->psk, PMK_LEN);
@@ -2293,6 +2282,31 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0;
}
+ if (os_strcmp(var, "eap") == 0) {
+ struct eap_method_type method;
+ method.method = eap_peer_get_type(value, &method.vendor);
+ if (method.vendor == EAP_VENDOR_IETF &&
+ method.method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+ "for a credential", line, value);
+ return -1;
+ }
+ os_free(cred->eap_method);
+ cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+ if (cred->eap_method == NULL)
+ return -1;
+ os_memcpy(cred->eap_method, &method, sizeof(method));
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0 &&
+ os_strncmp(value, "ext:", 4) == 0) {
+ os_free(cred->password);
+ cred->password = os_strdup(value);
+ cred->ext_password = 1;
+ return 0;
+ }
+
val = wpa_config_parse_string(value, &len);
if (val == NULL) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
@@ -2315,6 +2329,7 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
if (os_strcmp(var, "password") == 0) {
os_free(cred->password);
cred->password = val;
+ cred->ext_password = 0;
return 0;
}
@@ -2360,6 +2375,32 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0;
}
+ if (os_strcmp(var, "phase1") == 0) {
+ os_free(cred->phase1);
+ cred->phase1 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "phase2") == 0) {
+ os_free(cred->phase2);
+ cred->phase2 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "roaming_consortium length %d (3..15 "
+ "expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->roaming_consortium, val, len);
+ cred->roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
@@ -2530,6 +2571,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
struct wpa_config *config;
+ const int aCWmin = 4, aCWmax = 10;
+ const struct hostapd_wmm_ac_params ac_bk =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wmm_ac_params ac_be =
+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -2539,11 +2589,16 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
+ config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
config->max_num_sta = DEFAULT_MAX_NUM_STA;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+ config->wmm_ac_params[0] = ac_be;
+ config->wmm_ac_params[1] = ac_bk;
+ config->wmm_ac_params[2] = ac_vi;
+ config->wmm_ac_params[3] = ac_vo;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2836,7 +2891,8 @@ static int wpa_config_process_p2p_pref_chan(
pos2++;
chan = atoi(pos2);
- n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel));
+ n = os_realloc_array(pref, num + 1,
+ sizeof(struct p2p_channel));
if (n == NULL)
goto fail;
pref = n;
@@ -2950,6 +3006,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(bss_expiration_age), 0 },
{ INT(bss_expiration_scan_count), 0 },
{ INT_RANGE(filter_ssids, 0, 1), 0 },
+ { INT_RANGE(filter_rssi, -100, 0), 0 },
{ INT(max_num_sta), 0 },
{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
#ifdef CONFIG_HS20
@@ -2963,7 +3020,10 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
{ BIN(wps_nfc_dh_pubkey), 0 },
{ BIN(wps_nfc_dh_privkey), 0 },
- { BIN(wps_nfc_dev_pw), 0 }
+ { BIN(wps_nfc_dev_pw), 0 },
+ { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+ { INT(p2p_go_max_inactivity), 0 },
+ { INT_RANGE(auto_interworking, 0, 1), 0 },
};
#undef FUNC
@@ -2998,6 +3058,25 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
break;
}
if (i == NUM_GLOBAL_FIELDS) {
+#ifdef CONFIG_AP
+ if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
+ char *tmp = os_strchr(pos, '=');
+ if (tmp == NULL) {
+ if (line < 0)
+ return -1;
+ wpa_printf(MSG_ERROR, "Line %d: invalid line "
+ "'%s'", line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+ "AC item", line);
+ return -1;
+ }
+ }
+#endif /* CONFIG_AP */
if (line < 0)
return -1;
wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 46c4da24..b889ab81 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -18,6 +18,7 @@
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
+#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
#define DEFAULT_BSS_MAX_COUNT 200
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
@@ -26,6 +27,7 @@
#include "config_ssid.h"
#include "wps/wps.h"
+#include "common/ieee802_11_common.h"
struct wpa_cred {
@@ -81,6 +83,11 @@ struct wpa_cred {
char *password;
/**
+ * ext_password - Whether password is a name for external storage
+ */
+ int ext_password;
+
+ /**
* ca_cert - CA certificate for Interworking network selection
*/
char *ca_cert;
@@ -148,6 +155,47 @@ struct wpa_cred {
* whether the AP is operated by the Home SP.
*/
char *domain;
+
+ /**
+ * roaming_consortium - Roaming Consortium OI
+ *
+ * If roaming_consortium_len is non-zero, this field contains the
+ * Roaming Consortium OI that can be used to determine which access
+ * points support authentication with this credential. This is an
+ * alternative to the use of the realm parameter. When using Roaming
+ * Consortium to match the network, the EAP parameters need to be
+ * pre-configured with the credential since the NAI Realm information
+ * may not be available or fetched.
+ */
+ u8 roaming_consortium[15];
+
+ /**
+ * roaming_consortium_len - Length of roaming_consortium
+ */
+ size_t roaming_consortium_len;
+
+ /**
+ * eap_method - EAP method to use
+ *
+ * Pre-configured EAP method to use with this credential or %NULL to
+ * indicate no EAP method is selected, i.e., the method will be
+ * selected automatically based on ANQP information.
+ */
+ struct eap_method_type *eap_method;
+
+ /**
+ * phase1 - Phase 1 (outer authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase1;
+
+ /**
+ * phase2 - Phase 2 (inner authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase2;
};
@@ -165,6 +213,7 @@ struct wpa_cred {
#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -575,6 +624,14 @@ struct wpa_config {
int filter_ssids;
/**
+ * filter_rssi - RSSI-based scan result filtering
+ *
+ * 0 = do not filter scan results
+ * -n = filter scan results below -n dBm
+ */
+ int filter_rssi;
+
+ /**
* max_num_sta - Maximum number of STAs in an AP/P2P GO
*/
unsigned int max_num_sta;
@@ -661,6 +718,35 @@ struct wpa_config {
* wps_nfc_dh_pubkey - NFC Device Password for password token
*/
struct wpabuf *wps_nfc_dev_pw;
+
+ /**
+ * ext_password_backend - External password backend or %NULL if none
+ *
+ * format: <backend name>[:<optional backend parameters>]
+ */
+ char *ext_password_backend;
+
+ /*
+ * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in P2P GO mode to clean up
+ * inactive stations.
+ * By default: 300 seconds.
+ */
+ int p2p_go_max_inactivity;
+
+ struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+ /**
+ * auto_interworking - Whether to use network selection automatically
+ *
+ * 0 = do not automatically go through Interworking network selection
+ * (i.e., require explicit interworking_select command for this)
+ * 1 = perform Interworking network selection if one or more
+ * credentials have been configured and scan did not find a
+ * matching network block
+ */
+ int auto_interworking;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 8badc7b9..531957a9 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -19,6 +19,29 @@
#include "p2p/p2p.h"
+static int newline_terminated(const char *buf, size_t buflen)
+{
+ size_t len = os_strlen(buf);
+ if (len == 0)
+ return 0;
+ if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+ buf[len - 1] != '\n')
+ return 0;
+ return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+ char buf[100];
+ while (fgets(buf, sizeof(buf), stream)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (newline_terminated(buf, sizeof(buf)))
+ return;
+ }
+}
+
+
/**
* wpa_config_get_line - Read the next configuration file line
* @s: Buffer for the line
@@ -41,6 +64,15 @@ static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
while (fgets(s, size, stream)) {
(*line)++;
s[size - 1] = '\0';
+ if (!newline_terminated(s, size)) {
+ /*
+ * The line was truncated - skip rest of it to avoid
+ * confusing error messages.
+ */
+ wpa_printf(MSG_INFO, "Long line in configuration file "
+ "truncated");
+ skip_line_end(stream);
+ }
pos = s;
/* Skip white space from the beginning of line. */
@@ -99,12 +131,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
wpa_config_update_psk(ssid);
}
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
- "management, but no PSK configured.", line);
- errors++;
- }
-
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
@@ -123,7 +149,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
{
struct wpa_ssid *ssid;
int errors = 0, end = 0;
- char buf[256], *pos, *pos2;
+ char buf[2000], *pos, *pos2;
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
*line);
@@ -329,11 +355,17 @@ struct wpa_config * wpa_config_read(const char *name)
int cred_id = 0;
config = wpa_config_alloc_empty(NULL, NULL);
- if (config == NULL)
+ if (config == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate config file "
+ "structure");
return NULL;
+ }
+
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
os_free(config);
return NULL;
}
@@ -378,6 +410,8 @@ struct wpa_config * wpa_config_read(const char *name)
} else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
if (wpa_config_process_blob(config, f, &line, pos + 12)
< 0) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "process blob.", line);
errors++;
continue;
}
@@ -875,6 +909,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+
+ if (config->ext_password_backend)
+ fprintf(f, "ext_password_backend=%s\n",
+ config->ext_password_backend);
+ if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY)
+ fprintf(f, "p2p_go_max_inactivity=%d\n",
+ config->p2p_go_max_inactivity);
+ if (config->auto_interworking)
+ fprintf(f, "auto_interworking=%d\n",
+ config->auto_interworking);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 08636071..ff973793 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -141,6 +141,14 @@ struct wpa_ssid {
char *passphrase;
/**
+ * ext_psk - PSK/passphrase name in external storage
+ *
+ * If this is set, PSK/passphrase will be fetched from external storage
+ * when requesting association with the network.
+ */
+ char *ext_psk;
+
+ /**
* pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
*/
int pairwise_cipher;
@@ -356,6 +364,8 @@ struct wpa_ssid {
*/
int frequency;
+ int ht40;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -421,6 +431,10 @@ struct wpa_ssid {
*/
size_t num_p2p_clients;
+#ifndef P2P_MAX_STORED_CLIENTS
+#define P2P_MAX_STORED_CLIENTS 100
+#endif /* P2P_MAX_STORED_CLIENTS */
+
/**
* p2p_group - Network generated as a P2P group (used internally)
*/
@@ -512,6 +526,16 @@ struct wpa_ssid {
* By default: 2
*/
int dtim_period;
+
+ /**
+ * auth_failures - Number of consecutive authentication failures
+ */
+ unsigned int auth_failures;
+
+ /**
+ * disabled_until - Network block disabled until this time if non-zero
+ */
+ struct os_time disabled_until;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index de2ec58b..6d9876cc 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -344,13 +344,6 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
wpa_config_update_psk(ssid);
}
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
- "but no PSK configured for network '" TSTR "'.",
- netw);
- errors++;
- }
-
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 041685a4..059c586d 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -29,6 +30,7 @@
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
#include "hs20_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
@@ -98,6 +100,9 @@ static int pno_start(struct wpa_supplicant *wpa_s)
ssid = ssid->next;
}
+ if (wpa_s->conf->filter_rssi)
+ params.filter_rssi = wpa_s->conf->filter_rssi;
+
ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
os_free(params.filter_ssids);
if (ret == 0)
@@ -130,7 +135,7 @@ static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
os_free(filter);
return -1;
}
- n = os_realloc(filter, (count + 1) * ETH_ALEN);
+ n = os_realloc_array(filter, count + 1, ETH_ALEN);
if (n == NULL) {
os_free(filter);
return -1;
@@ -280,6 +285,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
}
} else if (os_strcasecmp(cmd, "ps") == 0) {
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(wpa_s->global, !!atoi(value));
+#endif /* CONFIG_WIFI_DISPLAY */
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
ret = set_bssid_filter(wpa_s, value);
} else {
@@ -307,6 +316,14 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
res = os_snprintf(buf, buflen, "%c%c",
wpa_s->conf->country[0],
wpa_s->conf->country[1]);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ res = os_snprintf(buf, buflen, "%d",
+ wpa_s->global->wifi_display);
+ if (res < 0 || (unsigned int) res >= buflen)
+ return -1;
+ return res;
+#endif /* CONFIG_WIFI_DISPLAY */
}
if (res < 0 || (unsigned int) res >= buflen)
@@ -1121,7 +1138,9 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_HS20
if (wpa_s->current_bss &&
- wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE)) {
+ wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+ wpa_s->wpa_proto == WPA_PROTO_RSN &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
ret = os_snprintf(pos, end - pos, "hs20=1\n");
if (ret < 0 || ret >= end - pos)
return pos - buf;
@@ -1377,10 +1396,12 @@ static int wpa_supplicant_ctrl_iface_list_networks(
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- ret = os_snprintf(pos, end - pos, "\t%s%s%s",
+ ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
ssid == wpa_s->current_ssid ?
"[CURRENT]" : "",
ssid->disabled ? "[DISABLED]" : "",
+ ssid->disabled_until.sec ?
+ "[TEMP-DISABLED]" : "",
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
"");
if (ret < 0 || ret >= end - pos)
@@ -1441,6 +1462,13 @@ static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
pos += ret;
first = 0;
}
+ if (cipher & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
+ first = 0;
+ }
return pos;
}
@@ -1640,7 +1668,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
pos += ret;
}
#ifdef CONFIG_HS20
- if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
ret = os_snprintf(pos, end - pos, "[HS20]");
if (ret < 0 || ret >= end - pos)
return -1;
@@ -2163,6 +2191,14 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
first = 0;
}
+ if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
if (ret < 0 || ret >= end - pos)
@@ -2211,6 +2247,14 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
first = 0;
}
+ if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
if (ret < 0 || ret >= end - pos)
@@ -2406,7 +2450,7 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
hmode = "A";
break;
default:
- return pos - buf;
+ continue;
}
ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
if (ret < 0 || ret >= end - pos)
@@ -2414,6 +2458,8 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
pos += ret;
chnl = wpa_s->hw.modes[j].channels;
for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+ if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
if (ret < 0 || ret >= end - pos)
return pos - buf;
@@ -2715,6 +2761,31 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
+ struct wpabuf *wfd;
+ ie = (const u8 *) (bss + 1);
+ wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
+ WFD_IE_VENDOR_TYPE);
+ if (wfd) {
+ ret = os_snprintf(pos, end - pos, "wfd_subelems=");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(wfd),
+ wpabuf_len(wfd));
+ wpabuf_free(wfd);
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
#ifdef CONFIG_INTERWORKING
if (mask & WPA_BSS_MASK_INTERNETW) {
pos = anqp_add_hex(pos, end, "anqp_venue_name",
@@ -2991,6 +3062,7 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
u8 dev_id[ETH_ALEN], *_dev_id = NULL;
char *pos;
+ unsigned int search_delay;
if (os_strstr(cmd, "type=social"))
type = P2P_FIND_ONLY_SOCIAL;
@@ -3005,7 +3077,15 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
_dev_id = dev_id;
}
- return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id);
+ pos = os_strstr(cmd, "delay=");
+ if (pos) {
+ pos += 6;
+ search_delay = atoi(pos);
+ } else
+ search_delay = wpas_p2p_search_delay(wpa_s);
+
+ return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
+ search_delay);
}
@@ -3025,10 +3105,12 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int go_intent = -1;
int freq = 0;
int pd;
+ int ht40;
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
* [persistent|persistent=<network id>]
- * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */
+ * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+ * [ht40] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -3056,6 +3138,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
+ ht40 = os_strstr(pos, " ht40") != NULL;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -3095,7 +3178,8 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
- auth, go_intent, freq, persistent_id, pd);
+ auth, go_intent, freq, persistent_id, pd,
+ ht40);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -3195,6 +3279,10 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
return -1;
pos++;
ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
+ ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
+#endif /* CONFIG_WIFI_DISPLAY */
} else {
len = os_strlen(pos);
if (len & 1)
@@ -3517,7 +3605,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- char *cmd, int freq)
+ char *cmd, int freq, int ht40)
{
int id;
struct wpa_ssid *ssid;
@@ -3531,26 +3619,31 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0;
+ int freq = 0, ht40;
char *pos;
pos = os_strstr(cmd, "freq=");
if (pos)
freq = atoi(pos + 5);
+ ht40 = os_strstr(cmd, "ht40") != NULL;
+
if (os_strncmp(cmd, "persistent=", 11) == 0)
- return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
+ return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
+ ht40);
if (os_strcmp(cmd, "persistent") == 0 ||
os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq);
+ return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
if (os_strncmp(cmd, "freq=", 5) == 0)
- return wpas_p2p_group_add(wpa_s, 0, freq);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ if (ht40)
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
cmd);
@@ -3653,8 +3746,8 @@ static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
*/
pos = param;
while (pos && pos[0]) {
- n = os_realloc(freq,
- (count + 1) * sizeof(struct wpa_freq_range));
+ n = os_realloc_array(freq, count + 1,
+ sizeof(struct wpa_freq_range));
if (n == NULL) {
os_free(freq);
return -1;
@@ -3957,6 +4050,122 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
return anqp_send_req(wpa_s, dst_addr, id, num_id);
}
+
+
+static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ struct wpabuf *advproto, *query = NULL;
+ int used, ret = -1;
+ char *pos, *end;
+ size_t len;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+
+ /* Advertisement Protocol ID */
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+ if (len == 0)
+ return -1;
+ advproto = wpabuf_alloc(len);
+ if (advproto == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
+ goto fail;
+
+ if (end) {
+ /* Optional Query Request */
+ pos = end + 1;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len) {
+ if (len & 0x01)
+ goto fail;
+ len /= 2;
+ if (len == 0)
+ goto fail;
+ query = wpabuf_alloc(len);
+ if (query == NULL)
+ goto fail;
+ if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
+ goto fail;
+ }
+ }
+
+ ret = gas_send_request(wpa_s, dst_addr, advproto, query);
+
+fail:
+ wpabuf_free(advproto);
+ wpabuf_free(query);
+
+ return ret;
+}
+
+
+static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ int dialog_token;
+ int used;
+ char *pos;
+ size_t resp_len, start, requested_len;
+
+ if (!wpa_s->last_gas_resp)
+ return -1;
+
+ used = hwaddr_aton2(cmd, addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+ dialog_token = atoi(pos);
+
+ if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
+ dialog_token != wpa_s->last_gas_dialog_token)
+ return -1;
+
+ resp_len = wpabuf_len(wpa_s->last_gas_resp);
+ start = 0;
+ requested_len = resp_len;
+
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ start = atoi(pos);
+ if (start > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ requested_len = atoi(pos);
+ if (start + requested_len > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ }
+
+ if (requested_len * 2 + 1 > buflen)
+ return os_snprintf(buf, buflen, "FAIL-Too long response");
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(wpa_s->last_gas_resp) + start,
+ requested_len);
+}
#endif /* CONFIG_INTERWORKING */
@@ -4185,6 +4394,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
+ } else if (os_strcmp(buf, "IFNAME") == 0) {
+ reply_len = os_strlen(wpa_s->ifname);
+ os_memcpy(reply, wpa_s->ifname, reply_len);
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
@@ -4375,7 +4587,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_p2p_group_remove(wpa_s, buf + 17))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
- if (wpas_p2p_group_add(wpa_s, 0, 0))
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -4447,6 +4659,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
reply_len = -1;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
+ if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
+ reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
+ reply, reply_size);
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
if (interworking_fetch_anqp(wpa_s) < 0)
@@ -4463,6 +4683,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
if (get_anqp(wpa_s, buf + 9) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
+ if (gas_request(wpa_s, buf + 12) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
+ reply_len = gas_response_get(wpa_s, buf + 17, reply,
+ reply_size);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
} else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index c831e6c9..994f9b18 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -163,6 +163,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -174,6 +176,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -266,6 +270,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -285,13 +290,25 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port--;
+ if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -442,6 +459,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -453,6 +472,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -502,6 +523,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
struct ctrl_iface_global_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_GLOBAL_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -523,13 +545,26 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port++;
+ if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
+ WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 67a0a8b1..5d81b43b 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -11,6 +11,8 @@
#include <sys/stat.h>
#include <grp.h>
#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
#ifdef ANDROID
#include <cutils/sockets.h>
#endif /* ANDROID */
@@ -282,6 +284,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
char *buf, *dir = NULL, *gid_str = NULL;
struct group *grp;
char *endp;
+ int flags;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -428,6 +431,20 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
#ifdef ANDROID
havesock:
#endif /* ANDROID */
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ perror("fcntl(ctrl, O_NONBLOCK)");
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 67924e0b..61a94304 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -738,7 +738,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
entry->bytearray_value = NULL;
entry->array_type = DBUS_TYPE_BYTE;
- buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
if (!buffer)
return FALSE;
@@ -748,8 +748,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
char byte;
if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
- (count + BYTE_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + BYTE_ARRAY_CHUNK_SIZE,
+ BYTE_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -795,7 +796,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
entry->strarray_value = NULL;
entry->array_type = DBUS_TYPE_STRING;
- buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
if (buffer == NULL)
return FALSE;
@@ -806,8 +807,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
char *str;
if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
- (count + STR_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + STR_ARRAY_CHUNK_SIZE,
+ STR_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -871,8 +873,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
buflen += BIN_ARRAY_CHUNK_SIZE;
- newbuf = os_realloc(entry->binarray_value,
- buflen * BIN_ARRAY_ITEM_SIZE);
+ newbuf = os_realloc_array(entry->binarray_value,
+ buflen, BIN_ARRAY_ITEM_SIZE);
if (!newbuf)
goto cleanup;
entry->binarray_value = newbuf;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index a9957abb..4eeb93a4 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1104,7 +1104,6 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
iface = wpa_s->parent->global->dbus;
@@ -1142,14 +1141,8 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
client ? "client" : "GO"))
goto nomem;
- os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
- wpa_s->parent->dbus_new_path, network_id);
-
if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
group_obj_path) ||
- !wpa_dbus_dict_append_object_path(&dict_iter, "network_object",
- net_obj_path) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
goto nomem;
@@ -2391,6 +2384,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+ {
+ END_ARGS
+ }
+ },
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 8145a702..5668e1a1 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -609,6 +609,7 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
out:
os_free(driver);
os_free(ifname);
+ os_free(confname);
os_free(bridge_ifname);
return reply;
@@ -870,7 +871,7 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
num++;
- paths = os_zalloc(num * sizeof(char*));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -1158,8 +1159,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
#define FREQS_ALLOC_CHUNK 32
if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
- nfreqs = os_realloc(freqs, sizeof(int) *
- (freqs_num + FREQS_ALLOC_CHUNK));
+ nfreqs = os_realloc_array(
+ freqs, freqs_num + FREQS_ALLOC_CHUNK,
+ sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
@@ -1179,8 +1181,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
dbus_message_iter_next(&array_iter);
}
- nfreqs = os_realloc(freqs,
- sizeof(int) * (freqs_num + 1));
+ nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
@@ -1404,6 +1405,33 @@ err:
/**
+ * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Reassociate" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->current_ssid != NULL) {
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return NULL;
+ }
+
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+ "This interface is not connected");
+}
+
+
+/**
* wpas_dbus_handler_remove_network - Remove a configured network
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
@@ -1901,6 +1929,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
goto nomem;
}
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip"))
@@ -1942,6 +1976,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
goto nomem;
}
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip"))
@@ -2430,7 +2470,7 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age;
+ dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
&expire_count, error);
@@ -2759,7 +2799,7 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
unsigned int i = 0;
dbus_bool_t success = FALSE;
- paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+ paths = os_calloc(wpa_s->num_bss, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -2822,7 +2862,7 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
if (!network_is_persistent_group(ssid))
num++;
- paths = os_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -3154,7 +3194,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
- const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
+ const char *pairwise[3]; /* max 3 pairwise ciphers is supported */
const char *key_mgmt[7]; /* max 7 key managements may be supported */
int n;
@@ -3197,6 +3237,9 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
case WPA_CIPHER_CCMP:
group = "ccmp";
break;
+ case WPA_CIPHER_GCMP:
+ group = "gcmp";
+ break;
case WPA_CIPHER_WEP104:
group = "wep104";
break;
@@ -3214,6 +3257,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
pairwise[n++] = "tkip";
if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
pairwise[n++] = "ccmp";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
+ pairwise[n++] = "gcmp";
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
pairwise, n))
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index cff218f3..178a76b7 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -94,6 +94,9 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index f4541f73..aee8b3a5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -127,7 +127,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
}
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL);
+ NULL, 0);
os_free(req_dev_types);
return reply;
@@ -346,13 +346,13 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
- } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0))
goto inv_args;
out:
@@ -504,7 +504,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, -1, 0);
+ go_intent, freq, -1, 0, 0);
if (new_pin >= 0) {
char npin[9];
@@ -1049,7 +1049,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
* Now construct the peer object paths in a form suitable for
* array_property_getter helper below.
*/
- peer_obj_paths = os_zalloc(num * sizeof(char *));
+ peer_obj_paths = os_calloc(num, sizeof(char *));
if (!peer_obj_paths) {
out_of_mem = 1;
@@ -1509,7 +1509,7 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
if (network_is_persistent_group(ssid))
num++;
- paths = os_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -1816,7 +1816,7 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
num_members = p2p_get_group_num_members(wpa_s->p2p_group);
- paths = os_zalloc(num_members * sizeof(char *));
+ paths = os_calloc(num_members, sizeof(char *));
if (!paths)
goto out_of_memory;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index fe1401f7..711b4073 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -232,6 +232,7 @@ CONFIG_SMARTCARD=y
# unix = UNIX domain sockets (default for Linux/*BSD)
# udp = UDP sockets using localhost (127.0.0.1)
# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
# y = use default (backwards compatibility)
# If this option is commented out, control interface is not included in the
# build.
@@ -505,10 +506,18 @@ CONFIG_PEERKEY=y
# Autoscan
# This can be used to enable automatic scan support in wpa_supplicant.
-# See wpa_supplicant.conf for more information on autoscan usage.
+# See wpa_supplicant.conf for more information on autoscan usage.
#
# Enabling directly a module will enable autoscan support.
# For exponential module:
#CONFIG_AUTOSCAN_EXPONENTIAL=y
# For periodic module:
#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 82a7bcb1..ee9f6b05 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -698,4 +698,14 @@ static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
}
+static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
+ enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len)
+{
+ if (!wpa_s->driver->wnm_oper)
+ return -1;
+ return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
+ buf_len);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index c220aec4..d1eb4ff3 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -35,6 +35,11 @@ int eap_register_methods(void)
ret = eap_peer_tls_register();
#endif /* EAP_TLS */
+#ifdef EAP_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_peer_unauth_tls_register();
+#endif /* EAP_UNAUTH_TLS */
+
#ifdef EAP_MSCHAPv2
if (ret == 0)
ret = eap_peer_mschapv2_register();
@@ -145,6 +150,11 @@ int eap_register_methods(void)
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
+#ifdef EAP_SERVER_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index e53e1563..7d63c1b4 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -13,6 +13,7 @@
#include <assert.h>
#include "common.h"
+#include "utils/ext_password.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
@@ -55,9 +56,8 @@ struct eapol_test_data {
struct radius_client_data *radius;
struct hostapd_radius_servers *radius_conf;
- u8 *last_eap_radius; /* last received EAP Response from Authentication
- * Server */
- size_t last_eap_radius_len;
+ /* last received EAP Response from Authentication Server */
+ struct wpabuf *last_eap_radius;
u8 authenticator_pmk[PMK_LEN];
size_t authenticator_pmk_len;
@@ -488,7 +488,7 @@ static void test_eapol_clean(struct eapol_test_data *e,
struct extra_radius_attr *p, *prev;
radius_client_deinit(e->radius);
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
radius_msg_free(e->last_recv_radius);
e->last_recv_radius = NULL;
os_free(e->eap_identity);
@@ -506,6 +506,10 @@ static void test_eapol_clean(struct eapol_test_data *e,
wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
wpa_s->ctrl_iface = NULL;
}
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+
wpa_config_free(wpa_s->conf);
p = e->extra_attrs;
@@ -574,9 +578,8 @@ static char *eap_type_text(u8 type)
static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
{
- u8 *eap;
- size_t len;
- struct eap_hdr *hdr;
+ struct wpabuf *eap;
+ const struct eap_hdr *hdr;
int eap_type = -1;
char buf[64];
struct radius_msg *msg;
@@ -586,30 +589,29 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
msg = e->last_recv_radius;
- eap = radius_msg_get_eap(msg, &len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
/* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
wpa_printf(MSG_DEBUG, "could not extract "
"EAP-Message from RADIUS message");
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
e->last_eap_radius = NULL;
- e->last_eap_radius_len = 0;
return;
}
- if (len < sizeof(*hdr)) {
+ if (wpabuf_len(eap) < sizeof(*hdr)) {
wpa_printf(MSG_DEBUG, "too short EAP packet "
"received from authentication server");
- os_free(eap);
+ wpabuf_free(eap);
return;
}
- if (len > sizeof(*hdr))
- eap_type = eap[sizeof(*hdr)];
+ if (wpabuf_len(eap) > sizeof(*hdr))
+ eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
- hdr = (struct eap_hdr *) eap;
+ hdr = wpabuf_head(eap);
switch (hdr->code) {
case EAP_CODE_REQUEST:
os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
@@ -632,7 +634,7 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
break;
default:
os_strlcpy(buf, "unknown EAP code", sizeof(buf));
- wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len);
+ wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
break;
}
wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
@@ -641,20 +643,21 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
e->last_eap_radius = eap;
- e->last_eap_radius_len = len;
{
struct ieee802_1x_hdr *dot1x;
- dot1x = os_malloc(sizeof(*dot1x) + len);
+ dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap));
assert(dot1x != NULL);
dot1x->version = EAPOL_VERSION;
dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
- dot1x->length = htons(len);
- os_memcpy((u8 *) (dot1x + 1), eap, len);
+ dot1x->length = htons(wpabuf_len(eap));
+ os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap),
+ wpabuf_len(eap));
eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
- (u8 *) dot1x, sizeof(*dot1x) + len);
+ (u8 *) dot1x,
+ sizeof(*dot1x) + wpabuf_len(eap));
os_free(dot1x);
}
}
@@ -1228,6 +1231,9 @@ int main(int argc, char *argv[])
if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
return -1;
+ if (wpas_init_ext_pw(&wpa_s) < 0)
+ return -1;
+
if (wait_for_monitor)
wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 451bfd47..a6100082 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -23,6 +23,7 @@
#include "eap_peer/eap.h"
#include "ap/hostapd.h"
#include "p2p/p2p.h"
+#include "wnm_sta.h"
#include "notify.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -40,11 +41,31 @@
#include "bss.h"
#include "scan.h"
#include "offchannel.h"
+#include "interworking.h"
+
+
+static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct os_time now;
+
+ if (ssid == NULL || ssid->disabled_until.sec == 0)
+ return 0;
+
+ os_get_time(&now);
+ if (ssid->disabled_until.sec > now.sec)
+ return ssid->disabled_until.sec - now.sec;
+
+ wpas_clear_temp_disabled(wpa_s, ssid, 0);
+
+ return 0;
+}
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid, *old_ssid;
+ int res;
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
return 0;
@@ -63,6 +84,13 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
return -1;
}
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
+ "disabled for %d second(s)", res);
+ return -1;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
"current AP");
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
@@ -148,6 +176,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
wpa_s->ap_ies_from_associnfo = 0;
+ wpa_s->current_ssid = NULL;
+ wpa_s->key_mgmt = 0;
}
@@ -450,6 +480,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
return 1;
}
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
+ !rsn_ie) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X");
+ return 1;
+ }
+
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
@@ -648,12 +684,20 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
+ int res;
if (wpas_network_disabled(wpa_s, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
+ "temporarily for %d second(s)", res);
+ continue;
+ }
+
#ifdef CONFIG_WPS
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
@@ -1032,7 +1076,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
#else
if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
#endif
- wpa_s->global->p2p != NULL) {
+ wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending) {
wpa_s->p2p_cb_on_scan_complete = 0;
if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
@@ -1040,6 +1084,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return -1;
}
}
+ wpa_s->sta_scan_pending = 0;
#endif /* CONFIG_P2P */
scan_res = wpa_supplicant_get_scan_results(wpa_s,
@@ -1134,6 +1179,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return 0;
}
+ wpas_wps_update_ap_info(wpa_s, scan_res);
+
selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
if (selected) {
@@ -1178,6 +1225,19 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return 0;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->auto_interworking &&
+ wpa_s->conf->interworking &&
+ wpa_s->conf->cred) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: "
+ "start ANQP fetch since no matching "
+ "networks found");
+ wpa_s->network_select = 1;
+ wpa_s->auto_network_select = 1;
+ interworking_start_fetch_anqp(wpa_s);
+ return 0;
+ }
+#endif /* CONFIG_INTERWORKING */
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
timeout_usec);
@@ -1548,7 +1608,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
{
u8 bssid[ETH_ALEN];
int ft_completed;
- int bssid_changed;
struct wpa_driver_capa capa;
#ifdef CONFIG_AP
@@ -1566,17 +1625,21 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
+ wpa_supplicant_disassociate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
- if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
- os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
random_add_randomness(bssid, ETH_ALEN);
- bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN);
os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
+ wpas_notify_bssid_changed(wpa_s);
if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
wpa_clear_keys(wpa_s, bssid);
@@ -1728,6 +1791,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
}
#endif /* CONFIG_IBSS_RSN */
+
+ wpas_wps_notify_assoc(wpa_s, bssid);
}
@@ -1767,6 +1832,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
+ wpas_auth_failed(wpa_s);
}
if (!wpa_s->auto_reconnect_disabled ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
@@ -2037,6 +2103,25 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_IEEE80211V
+static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (data == NULL)
+ return;
+ switch (data->wnm.oper) {
+ case WNM_OPER_SLEEP:
+ wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request "
+ "(action=%d, intval=%d)",
+ data->wnm.sleep_action, data->wnm.sleep_intval);
+ ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action,
+ data->wnm.sleep_intval);
+ break;
+ }
+}
+#endif /* CONFIG_IEEE80211V */
+
+
#ifdef CONFIG_IEEE80211R
static void
wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
@@ -2323,6 +2408,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
wpa_supplicant_event_disassoc(wpa_s, reason_code,
locally_generated);
+ if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+ ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+ (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+ eapol_sm_failed(wpa_s->eapol)))
+ wpas_auth_failed(wpa_s);
#ifdef CONFIG_P2P
if (event == EVENT_DEAUTH && data) {
wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr,
@@ -2339,6 +2429,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_RESULTS:
wpa_supplicant_event_scan_results(wpa_s, data);
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL &&
+ wpa_s->wpa_state != WPA_AUTHENTICATING &&
+ wpa_s->wpa_state != WPA_ASSOCIATING) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after scan result processing");
+ }
+ }
+#endif /* CONFIG_P2P */
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO:
@@ -2360,6 +2462,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_supplicant_event_tdls(wpa_s, data);
break;
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_IEEE80211V
+ case EVENT_WNM:
+ wpa_supplicant_event_wnm(wpa_s, data);
+ break;
+#endif /* CONFIG_IEEE80211V */
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RESPONSE:
wpa_supplicant_event_ft_response(wpa_s, data);
@@ -2585,6 +2692,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_SME */
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211V
+ if (data->rx_action.category == WLAN_ACTION_WNM) {
+ ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
+ break;
+ }
+#endif /* CONFIG_IEEE80211V */
#ifdef CONFIG_GAS
if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
gas_query_rx(wpa_s->gas, data->rx_action.da,
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
new file mode 100644
index 00000000..59b0a9d3
--- /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 00000000..c3e39b3d
--- /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 00000000..973d46ab
--- /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 00000000..ff8509d6
--- /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 00000000..5c8fdafd
--- /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 00000000..6deb397e
--- /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 00000000..bb3c1e49
--- /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 00000000..f6c03b02
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -0,0 +1,174 @@
+#!/usr/bin/python
+# Tests p2p_stop_find
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+def p2pStateChange(status):
+ print status
+ os._exit(0)
+
+class P2P_Stop_Find (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+ self.bus.add_signal_receiver(p2pStateChange,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="P2PStateChanged")
+
+ # Runs p2p_stop_find
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.StopFind()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+ # Needed because P2PStateChanged signal is not caught
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"ht:i:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_stop_find_test = P2P_Stop_Find(interface_name,
+ wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_stop_find_test.start()
+
+ try:
+ time.sleep(int(p2p_stop_find_test.timeout))
+
+ except:
+ pass
+
+ print "p2p find stopped"
+ quit()
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 1fd6e00e..efa9be8e 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -19,7 +19,7 @@
#include "gas_query.h"
-#define GAS_QUERY_TIMEOUT 5
+#define GAS_QUERY_TIMEOUT_PERIOD 5
struct gas_query_pending {
@@ -457,7 +457,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
return -1;
}
- eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout,
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
gas, query);
return dialog_token;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 515d94bb..7b5b20eb 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -15,6 +15,7 @@
#include "utils/pcsc_funcs.h"
#include "drivers/driver.h"
#include "eap_common/eap_defs.h"
+#include "eap_peer/eap.h"
#include "eap_peer/eap_methods.h"
#include "wpa_supplicant_i.h"
#include "config.h"
@@ -329,7 +330,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
wpa_printf(MSG_DEBUG, "No room for EAP Methods");
return NULL;
}
- r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
+ r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
if (r->eap == NULL)
return NULL;
@@ -365,7 +366,7 @@ static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
return NULL;
}
- realm = os_zalloc(num * sizeof(struct nai_realm));
+ realm = os_calloc(num, sizeof(struct nai_realm));
if (realm == NULL)
return NULL;
@@ -550,6 +551,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
break;
if (os_memcmp(pos, plmn, 3) == 0)
return 1; /* Found matching PLMN */
+ pos += 3;
}
}
@@ -561,7 +563,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
- char prefix)
+ size_t mnc_len, char prefix)
{
const char *sep, *msin;
char *end, *pos;
@@ -579,12 +581,16 @@ static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
return -1;
}
sep = os_strchr(imsi, '-');
- if (sep == NULL)
+ if (sep) {
+ plmn_len = sep - imsi;
+ msin = sep + 1;
+ } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
+ plmn_len = 3 + mnc_len;
+ msin = imsi + plmn_len;
+ } else
return -1;
- plmn_len = sep - imsi;
if (plmn_len != 5 && plmn_len != 6)
return -1;
- msin = sep + 1;
msin_len = os_strlen(msin);
pos = nai;
@@ -615,7 +621,7 @@ static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
{
char nai[100];
- if (build_root_nai(nai, sizeof(nai), imsi, prefix) < 0)
+ if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
return -1;
return wpa_config_set_quoted(ssid, "identity", nai);
}
@@ -623,6 +629,18 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
#endif /* INTERWORKING_3GPP */
+static int interworking_set_hs20_params(struct wpa_ssid *ssid)
+{
+ if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0)
+ return -1;
+ if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
+ return -1;
+ if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ return -1;
+ return 0;
+}
+
+
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
@@ -688,6 +706,9 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
+ if (interworking_set_hs20_params(ssid) < 0)
+ goto fail;
+
/* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
@@ -730,6 +751,255 @@ fail:
}
+static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
+ size_t rc_len)
+{
+ const u8 *pos, *end;
+ u8 lens;
+
+ if (ie == NULL)
+ return 0;
+
+ pos = ie + 2;
+ end = ie + 2 + ie[1];
+
+ /* Roaming Consortium element:
+ * Number of ANQP OIs
+ * OI #1 and #2 lengths
+ * OI #1, [OI #2], [OI #3]
+ */
+
+ if (pos + 2 > end)
+ return 0;
+
+ pos++; /* skip Number of ANQP OIs */
+ lens = *pos++;
+ if (pos + (lens & 0x0f) + (lens >> 4) > end)
+ return 0;
+
+ if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += lens & 0x0f;
+
+ if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += lens >> 4;
+
+ if (pos < end && (size_t) (end - pos) == rc_len &&
+ os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+
+ return 0;
+}
+
+
+static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
+ const u8 *rc_id, size_t rc_len)
+{
+ const u8 *pos, *end;
+ u8 len;
+
+ if (anqp == NULL)
+ return 0;
+
+ pos = wpabuf_head(anqp);
+ end = pos + wpabuf_len(anqp);
+
+ /* Set of <OI Length, OI> duples */
+ while (pos < end) {
+ len = *pos++;
+ if (pos + len > end)
+ break;
+ if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += len;
+ }
+
+ return 0;
+}
+
+
+static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
+ const u8 *rc_id, size_t rc_len)
+{
+ return roaming_consortium_element_match(ie, rc_id, rc_len) ||
+ roaming_consortium_anqp_match(anqp, rc_id, rc_len);
+}
+
+
+static struct wpa_cred * interworking_credentials_available_roaming_consortium(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_cred *cred, *selected = NULL;
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+ if (ie == NULL && bss->anqp_roaming_consortium == NULL)
+ return NULL;
+
+ if (wpa_s->conf->cred == NULL)
+ return NULL;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->roaming_consortium_len == 0)
+ continue;
+
+ if (!roaming_consortium_match(ie, bss->anqp_roaming_consortium,
+ cred->roaming_consortium,
+ cred->roaming_consortium_len))
+ continue;
+
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ }
+
+ return selected;
+}
+
+
+static int interworking_set_eap_params(struct wpa_ssid *ssid,
+ struct wpa_cred *cred, int ttls)
+{
+ if (cred->eap_method) {
+ ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
+ cred->eap_method->method == EAP_TYPE_TTLS;
+
+ os_free(ssid->eap.eap_methods);
+ ssid->eap.eap_methods =
+ os_malloc(sizeof(struct eap_method_type) * 2);
+ if (ssid->eap.eap_methods == NULL)
+ return -1;
+ os_memcpy(ssid->eap.eap_methods, cred->eap_method,
+ sizeof(*cred->eap_method));
+ ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
+ ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
+ }
+
+ if (ttls && cred->username && cred->username[0]) {
+ const char *pos;
+ char *anon;
+ /* Use anonymous NAI in Phase 1 */
+ pos = os_strchr(cred->username, '@');
+ if (pos) {
+ size_t buflen = 9 + os_strlen(pos) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous%s", pos);
+ } else if (cred->realm) {
+ size_t buflen = 10 + os_strlen(cred->realm) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+ } else {
+ anon = os_strdup("anonymous");
+ if (anon == NULL)
+ return -1;
+ }
+ if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
+ 0) {
+ os_free(anon);
+ return -1;
+ }
+ os_free(anon);
+ }
+
+ if (cred->username && cred->username[0] &&
+ wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
+ return -1;
+
+ if (cred->password && cred->password[0]) {
+ if (cred->ext_password &&
+ wpa_config_set(ssid, "password", cred->password, 0) < 0)
+ return -1;
+ if (!cred->ext_password &&
+ wpa_config_set_quoted(ssid, "password", cred->password) <
+ 0)
+ return -1;
+ }
+
+ if (cred->client_cert && cred->client_cert[0] &&
+ wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
+ return -1;
+
+ if (cred->private_key && cred->private_key[0] &&
+ wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+ return -1;
+
+ if (cred->private_key_passwd && cred->private_key_passwd[0] &&
+ wpa_config_set_quoted(ssid, "private_key_passwd",
+ cred->private_key_passwd) < 0)
+ return -1;
+
+ if (cred->phase1) {
+ os_free(ssid->eap.phase1);
+ ssid->eap.phase1 = os_strdup(cred->phase1);
+ }
+ if (cred->phase2) {
+ os_free(ssid->eap.phase2);
+ ssid->eap.phase2 = os_strdup(cred->phase2);
+ }
+
+ if (cred->ca_cert && cred->ca_cert[0] &&
+ wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int interworking_connect_roaming_consortium(
+ struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
+ struct wpa_bss *bss, const u8 *ssid_ie)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
+ "roaming consortium match", MAC2STR(bss->bssid));
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL)
+ return -1;
+ wpas_notify_network_added(wpa_s, ssid);
+ wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
+ ssid->temporary = 1;
+ ssid->ssid = os_zalloc(ssid_ie[1] + 1);
+ if (ssid->ssid == NULL)
+ goto fail;
+ os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
+ ssid->ssid_len = ssid_ie[1];
+
+ if (interworking_set_hs20_params(ssid) < 0)
+ goto fail;
+
+ if (cred->eap_method == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
+ "credential using roaming consortium");
+ goto fail;
+ }
+
+ if (interworking_set_eap_params(
+ ssid, cred,
+ cred->eap_method->vendor == EAP_VENDOR_IETF &&
+ cred->eap_method->method == EAP_TYPE_TTLS) < 0)
+ goto fail;
+
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
+
+ return 0;
+
+fail:
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return -1;
+}
+
+
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_cred *cred;
@@ -749,6 +1019,22 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
return -1;
}
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+ /*
+ * We currently support only HS 2.0 networks and those are
+ * required to use WPA2-Enterprise.
+ */
+ wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
+ "RSN");
+ return -1;
+ }
+
+ cred = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred)
+ return interworking_connect_roaming_consortium(wpa_s, cred,
+ bss, ie);
+
realm = nai_realm_parse(bss->anqp_nai_realm, &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
@@ -800,60 +1086,11 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
- if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
- eap->method), 0) < 0)
- goto fail;
-
- if (eap->method == EAP_TYPE_TTLS &&
- cred->username && cred->username[0]) {
- const char *pos;
- char *anon;
- /* Use anonymous NAI in Phase 1 */
- pos = os_strchr(cred->username, '@');
- if (pos) {
- size_t buflen = 9 + os_strlen(pos) + 1;
- anon = os_malloc(buflen);
- if (anon == NULL)
- goto fail;
- os_snprintf(anon, buflen, "anonymous%s", pos);
- } else if (cred->realm) {
- size_t buflen = 10 + os_strlen(cred->realm) + 1;
- anon = os_malloc(buflen);
- if (anon == NULL)
- goto fail;
- os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
- } else {
- anon = os_strdup("anonymous");
- if (anon == NULL)
- goto fail;
- }
- if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
- 0) {
- os_free(anon);
- goto fail;
- }
- os_free(anon);
- }
-
- if (cred->username && cred->username[0] &&
- wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
- goto fail;
-
- if (cred->password && cred->password[0] &&
- wpa_config_set_quoted(ssid, "password", cred->password) < 0)
- goto fail;
-
- if (cred->client_cert && cred->client_cert[0] &&
- wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
- goto fail;
-
- if (cred->private_key && cred->private_key[0] &&
- wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+ if (interworking_set_hs20_params(ssid) < 0)
goto fail;
- if (cred->private_key_passwd && cred->private_key_passwd[0] &&
- wpa_config_set_quoted(ssid, "private_key_passwd",
- cred->private_key_passwd) < 0)
+ if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
+ eap->method), 0) < 0)
goto fail;
switch (eap->method) {
@@ -899,8 +1136,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
break;
}
- if (cred->ca_cert && cred->ca_cert[0] &&
- wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
+ if (interworking_set_eap_params(ssid, cred,
+ eap->method == EAP_TYPE_TTLS) < 0)
goto fail;
nai_realm_free(realm, count);
@@ -1027,6 +1264,13 @@ static struct wpa_cred * interworking_credentials_available(
if (!cred)
cred = cred2;
+ cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred && cred2 && cred2->priority >= cred->priority)
+ cred = cred2;
+ if (!cred)
+ cred = cred2;
+
return cred;
}
@@ -1071,8 +1315,17 @@ static int interworking_home_sp(struct wpa_supplicant *wpa_s,
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
#ifdef INTERWORKING_3GPP
- if (cred->imsi &&
- build_root_nai(nai, sizeof(nai), cred->imsi, 0) == 0) {
+ char *imsi = NULL;
+ int mnc_len = 0;
+ if (cred->imsi)
+ imsi = cred->imsi;
+ else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
+ wpa_s->scard && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+ if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0)
+ == 0) {
realm = os_strchr(nai, '@');
if (realm)
realm++;
@@ -1138,6 +1391,16 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
cred = interworking_credentials_available(wpa_s, bss);
if (!cred)
continue;
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+ /*
+ * We currently support only HS 2.0 networks and those
+ * are required to use WPA2-Enterprise.
+ */
+ wpa_printf(MSG_DEBUG, "Interworking: Credential match "
+ "with " MACSTR " but network does not use "
+ "RSN", MAC2STR(bss->bssid));
+ continue;
+ }
count++;
res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
if (res > 0)
@@ -1148,7 +1411,9 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
type = "unknown";
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
MAC2STR(bss->bssid), type);
- if (wpa_s->auto_select) {
+ if (wpa_s->auto_select ||
+ (wpa_s->conf->auto_interworking &&
+ wpa_s->auto_network_select)) {
if (selected == NULL ||
cred->priority > selected_prio) {
selected = bss;
@@ -1178,7 +1443,16 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
if (interworking_find_network_match(wpa_s)) {
wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
"match for enabled network configurations");
- interworking_reconnect(wpa_s);
+ if (wpa_s->auto_select)
+ interworking_reconnect(wpa_s);
+ return;
+ }
+
+ if (wpa_s->auto_network_select) {
+ wpa_printf(MSG_DEBUG, "Interworking: Continue "
+ "scanning after ANQP fetch");
+ wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
+ 0);
return;
}
@@ -1226,7 +1500,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
}
-static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@@ -1484,6 +1758,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
{
interworking_stop_fetch_anqp(wpa_s);
wpa_s->network_select = 1;
+ wpa_s->auto_network_select = 0;
wpa_s->auto_select = !!auto_select;
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
@@ -1493,3 +1768,84 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
return 0;
}
+
+
+static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
+ " dialog_token=%d status_code=%d resp_len=%d",
+ MAC2STR(addr), dialog_token, status_code,
+ resp ? (int) wpabuf_len(resp) : -1);
+ if (!resp)
+ return;
+
+ wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = wpabuf_dup(resp);
+ if (wpa_s->last_gas_resp == NULL)
+ return;
+ os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
+ wpa_s->last_gas_dialog_token = dialog_token;
+}
+
+
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *query)
+{
+ struct wpabuf *buf;
+ int ret = 0;
+ int freq;
+ struct wpa_bss *bss;
+ int res;
+ size_t len;
+ u8 query_resp_len_limit = 0, pame_bi = 0;
+
+ freq = wpa_s->assoc_freq;
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+ if (bss)
+ freq = bss->freq;
+ if (freq <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
+ MAC2STR(dst), freq);
+ wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
+
+ len = 3 + wpabuf_len(adv_proto) + 2;
+ if (query)
+ len += wpabuf_len(query);
+ buf = gas_build_initial_req(0, len);
+ if (buf == NULL)
+ return -1;
+
+ /* Advertisement Protocol IE */
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
+ wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+ (pame_bi ? 0x80 : 0));
+ wpabuf_put_buf(buf, adv_proto);
+
+ /* GAS Query */
+ if (query) {
+ wpabuf_put_le16(buf, wpabuf_len(query));
+ wpabuf_put_buf(buf, query);
+ } else
+ wpabuf_put_le16(buf, 0);
+
+ res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+ ret = -1;
+ } else
+ wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
+ "%u", res);
+
+ wpabuf_free(buf);
+ return ret;
+}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 7dda8d82..cb8438e6 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -1,6 +1,6 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,9 +17,13 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code);
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *query);
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
#endif /* INTERWORKING_H */
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 80aac77b..19f7ce66 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -101,20 +101,31 @@ static void license(void)
}
-static void wpa_supplicant_fd_workaround(void)
+static void wpa_supplicant_fd_workaround(int start)
{
#ifdef __linux__
- int s, i;
+ static int fd[3] = { -1, -1, -1 };
+ int i;
/* When started from pcmcia-cs scripts, wpa_supplicant might start with
* fd 0, 1, and 2 closed. This will cause some issues because many
* places in wpa_supplicant are still printing out to stdout. As a
* workaround, make sure that fd's 0, 1, and 2 are not used for other
* sockets. */
- for (i = 0; i < 3; i++) {
- s = open("/dev/null", O_RDWR);
- if (s > 2) {
- close(s);
- break;
+ if (start) {
+ for (i = 0; i < 3; i++) {
+ fd[i] = open("/dev/null", O_RDWR);
+ if (fd[i] > 2) {
+ close(fd[i]);
+ fd[i] = -1;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 3; i++) {
+ if (fd[i] >= 0) {
+ close(fd[i]);
+ fd[i] = -1;
+ }
}
}
#endif /* __linux__ */
@@ -140,7 +151,7 @@ int main(int argc, char *argv[])
return -1;
iface_count = 1;
- wpa_supplicant_fd_workaround();
+ wpa_supplicant_fd_workaround(1);
for (;;) {
c = getopt(argc, argv,
@@ -241,8 +252,8 @@ int main(int argc, char *argv[])
break;
case 'N':
iface_count++;
- iface = os_realloc(ifaces, iface_count *
- sizeof(struct wpa_interface));
+ iface = os_realloc_array(ifaces, iface_count,
+ sizeof(struct wpa_interface));
if (iface == NULL)
goto out;
ifaces = iface;
@@ -288,6 +299,7 @@ int main(int argc, char *argv[])
wpa_supplicant_deinit(global);
out:
+ wpa_supplicant_fd_workaround(0);
os_free(ifaces);
os_free(params.pid_file);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 55cb2439..cfe04332 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -61,6 +61,27 @@
#define P2P_MAX_INITIAL_CONN_WAIT 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+#ifndef P2P_CONCURRENT_SEARCH_DELAY
+#ifdef ANDROID_P2P
+#define P2P_CONCURRENT_SEARCH_DELAY 0
+#else
+#define P2P_CONCURRENT_SEARCH_DELAY 500
+#endif
+#endif /* P2P_CONCURRENT_SEARCH_DELAY */
+
+enum p2p_group_removal_reason {
+ P2P_GROUP_REMOVAL_UNKNOWN,
+ P2P_GROUP_REMOVAL_SILENT,
+ P2P_GROUP_REMOVAL_FORMATION_FAILED,
+ P2P_GROUP_REMOVAL_REQUESTED,
+ P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
+ P2P_GROUP_REMOVAL_UNAVAILABLE,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
+#ifdef ANDROID_P2P
+ P2P_GROUP_REMOVAL_FREQ_CONFLICT
+#endif
+};
+
#ifdef ANDROID_P2P
static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s);
#endif
@@ -129,6 +150,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *ifs;
struct wpa_driver_scan_params params;
int ret;
struct wpabuf *wps_ie, *ies;
@@ -138,6 +160,18 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs->sta_scan_pending &&
+ wpas_p2p_in_progress(wpa_s) == 2) {
+ wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
+ "pending station mode scan to be "
+ "completed on interface %s", ifs->ifname);
+ wpa_s->p2p_cb_on_scan_complete = 1;
+ wpa_supplicant_req_scan(ifs, 0, 0);
+ return 1;
+ }
+ }
+
os_memset(&params, 0, sizeof(params));
/* P2P Wildcard SSID */
@@ -241,14 +275,19 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
}
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
+static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
+ enum p2p_group_removal_reason removal_reason)
{
struct wpa_ssid *ssid;
char *gtype;
const char *reason;
ssid = wpa_s->current_ssid;
+#ifdef ANDROID_P2P
+ if ((ssid == NULL) && (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) {
+#else
if (ssid == NULL) {
+#endif
/*
* The current SSID was not known, but there may still be a
* pending P2P group interface waiting for provisioning.
@@ -261,6 +300,11 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
break;
ssid = ssid->next;
}
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "P2P: P2P group interface "
+ "not found");
+ return -1;
+ }
}
if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO)
gtype = "GO";
@@ -279,10 +323,13 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
wpa_s->ifname, wpa_s->cross_connect_uplink);
}
- switch (wpa_s->removal_reason) {
+ switch (removal_reason) {
case P2P_GROUP_REMOVAL_REQUESTED:
reason = " reason=REQUESTED";
break;
+ case P2P_GROUP_REMOVAL_FORMATION_FAILED:
+ reason = " reason=FORMATION_FAILED";
+ break;
case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
reason = " reason=IDLE";
break;
@@ -301,7 +348,7 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
reason = "";
break;
}
- if (!silent) {
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_REMOVED "%s %s%s",
wpa_s->ifname, gtype, reason);
@@ -310,7 +357,7 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
- if (!silent && ssid)
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -327,7 +374,7 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
if (wpa_s && ifname)
wpa_drv_if_remove(wpa_s, type, ifname);
os_free(ifname);
- return;
+ return 0;
}
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
@@ -360,6 +407,8 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
wpa_supplicant_ap_deinit(wpa_s);
else
wpa_drv_deinit_p2p_cli(wpa_s);
+
+ return 0;
}
@@ -517,6 +566,7 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, *s;
u8 *n;
size_t i;
+ int found = 0;
ssid = wpa_s->current_ssid;
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
@@ -537,17 +587,40 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
- ETH_ALEN) == 0)
- return; /* already in list */
+ ETH_ALEN) != 0)
+ continue;
+
+ if (i == s->num_p2p_clients - 1)
+ return; /* already the most recent entry */
+
+ /* move the entry to mark it most recent */
+ os_memmove(s->p2p_client_list + i * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memcpy(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+ found = 1;
+ break;
}
- n = os_realloc(s->p2p_client_list,
- (s->num_p2p_clients + 1) * ETH_ALEN);
- if (n == NULL)
- return;
- os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
- s->p2p_client_list = n;
- s->num_p2p_clients++;
+ if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
+ n = os_realloc_array(s->p2p_client_list,
+ s->num_p2p_clients + 1, ETH_ALEN);
+ if (n == NULL)
+ return;
+ os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+ s->p2p_client_list = n;
+ s->num_p2p_clients++;
+ } else if (!found) {
+ /* Not enough room for an additional entry - drop the oldest
+ * entry */
+ os_memmove(s->p2p_client_list,
+ s->p2p_client_list + ETH_ALEN,
+ (s->num_p2p_clients - 1) * ETH_ALEN);
+ os_memcpy(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * ETH_ALEN,
+ addr, ETH_ALEN);
+ }
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->parent->conf->update_config &&
@@ -580,7 +653,8 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
if (!success) {
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_FORMATION_FAILED);
return;
}
@@ -835,6 +909,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
+ ssid->ht40 = params->ht40;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -845,6 +920,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
ssid->passphrase = os_strdup(params->passphrase);
+ ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
@@ -1032,6 +1108,9 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
return;
}
+ if (wpa_s->p2p_go_ht40)
+ res->ht40 = 1;
+
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
@@ -1449,6 +1528,62 @@ static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_WIFI_DISPLAY
+static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
+ struct wpabuf *resp, u8 srv_trans_id,
+ const u8 *query, size_t query_len)
+{
+ const u8 *pos;
+ u8 role;
+ u8 *len_pos;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
+
+ if (!wpa_s->global->wifi_display) {
+ wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
+ wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
+ srv_trans_id);
+ return;
+ }
+
+ if (query_len < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
+ "Role");
+ return;
+ }
+
+ if (wpabuf_tailroom(resp) < 5)
+ return;
+
+ pos = query;
+ role = *pos++;
+ wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
+
+ /* TODO: role specific handling */
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
+ wpabuf_put_u8(resp, srv_trans_id);
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
+
+ while (pos < query + query_len) {
+ if (*pos < MAX_WFD_SUBELEMS &&
+ wpa_s->global->wfd_subelem[*pos] &&
+ wpabuf_tailroom(resp) >=
+ wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
+ wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
+ "subelement %u", *pos);
+ wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
+ }
+ pos++;
+ }
+
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
u16 update_indic, const u8 *tlvs, size_t tlvs_len)
{
@@ -1540,6 +1675,12 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
pos, tlv_end - pos);
break;
+#ifdef CONFIG_WIFI_DISPLAY
+ case P2P_SERV_WIFI_DISPLAY:
+ wpas_sd_req_wfd(wpa_s, resp, srv_trans_id,
+ pos, tlv_end - pos);
+ break;
+#endif /* CONFIG_WIFI_DISPLAY */
default:
wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
"protocol %u", srv_proto);
@@ -1657,6 +1798,88 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
}
+#ifdef CONFIG_WIFI_DISPLAY
+
+static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *tlvs)
+{
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+ return 0;
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return 0;
+ return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+#define MAX_WFD_SD_SUBELEMS 20
+
+static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
+ const char *subelems)
+{
+ u8 *len;
+ const char *pos;
+ int val;
+ int count = 0;
+
+ len = wpabuf_put(tlvs, 2);
+ wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
+ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+
+ wpabuf_put_u8(tlvs, role);
+
+ pos = subelems;
+ while (*pos) {
+ val = atoi(pos);
+ if (val >= 0 && val < 256) {
+ wpabuf_put_u8(tlvs, val);
+ count++;
+ if (count == MAX_WFD_SD_SUBELEMS)
+ break;
+ }
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
+}
+
+
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *role)
+{
+ struct wpabuf *tlvs;
+ u64 ret;
+ const char *subelems;
+ u8 id = 1;
+
+ subelems = os_strchr(role, ' ');
+ if (subelems == NULL)
+ return 0;
+ subelems++;
+
+ tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
+ if (tlvs == NULL)
+ return 0;
+
+ if (os_strstr(role, "[source]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
+ if (os_strstr(role, "[pri-sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
+ if (os_strstr(role, "[sec-sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
+ if (os_strstr(role, "[source+sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
+
+ ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+ return ret;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
{
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
@@ -2084,7 +2307,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
MAC2STR(sa), op_freq);
if (s) {
wpas_p2p_group_add_persistent(
- wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
+ wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0);
} else if (bssid) {
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0);
@@ -2151,7 +2374,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
}
wpas_p2p_group_add_persistent(wpa_s, ssid,
- ssid->mode == WPAS_MODE_P2P_GO, 0);
+ ssid->mode == WPAS_MODE_P2P_GO, 0, 0);
}
@@ -2288,26 +2511,48 @@ struct p2p_oper_class_map {
enum { BW20, BW40PLUS, BW40MINUS } bw;
};
+static struct p2p_oper_class_map op_class[] = {
+ { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
+ { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
+#if 0 /* Do not enable HT40 on 2 GHz for now */
+ { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
+ { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
+#endif
+ { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
+ { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
+ { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
+ { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
+ { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
+ { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+ { -1, 0, 0, 0, 0, BW20 }
+};
+
+
+static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ int flag;
+
+ if (!has_channel(wpa_s->global, mode, channel, &flag))
+ return -1;
+ if (bw == BW40MINUS &&
+ (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
+ !has_channel(wpa_s->global, mode, channel - 4, NULL)))
+ return 0;
+ if (bw == BW40PLUS &&
+ (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
+ !has_channel(wpa_s->global, mode, channel + 4, NULL)))
+ return 0;
+ return 1;
+}
+
+
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan)
{
struct hostapd_hw_modes *mode;
int cla, op;
- struct p2p_oper_class_map op_class[] = {
- { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
- { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
-#if 0 /* Do not enable HT40 on 2 GHz for now */
- { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
-#endif
- { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
- { -1, 0, 0, 0, 0, BW20 }
- };
if (wpa_s->hw.modes == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
@@ -2327,16 +2572,7 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
if (mode == NULL)
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- int flag;
- if (!has_channel(wpa_s->global, mode, ch, &flag))
- continue;
- if (o->bw == BW40MINUS &&
- (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(wpa_s->global, mode, ch - 4, NULL)))
- continue;
- if (o->bw == BW40PLUS &&
- (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(wpa_s->global, mode, ch + 4, NULL)))
+ if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
continue;
if (reg == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2360,6 +2596,32 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
}
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ int op, ret;
+
+ for (op = 0; op_class[op].op_class; op++) {
+ struct p2p_oper_class_map *o = &op_class[op];
+ u8 ch;
+
+ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+ if (o->mode != HOSTAPD_MODE_IEEE80211A ||
+ o->bw == BW20 || ch != channel)
+ continue;
+ ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ if (ret < 0)
+ continue;
+ else if (ret > 0)
+ return (o->bw == BW40MINUS) ? -1 : 1;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -2540,7 +2802,6 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
-
#ifdef ANDROID_P2P
if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
@@ -2607,13 +2868,14 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s, *tmp;
+ wpa_s = global->ifaces;
+ if (wpa_s)
+ wpas_p2p_service_flush(wpa_s);
+
if (global->p2p == NULL)
return;
/* Remove remaining P2P group interfaces */
- wpa_s = global->ifaces;
- if (wpa_s)
- wpas_p2p_service_flush(wpa_s);
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
wpa_s = wpa_s->next;
while (wpa_s) {
@@ -2677,6 +2939,13 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
force_freq, persistent_group);
}
+ /*
+ * Increase GO config timeout if HT40 is used since it takes some time
+ * to scan channels for coex purposes before the BSS can be started.
+ */
+ p2p_set_config_timeout(wpa_s->global->p2p,
+ wpa_s->p2p_go_ht40 ? 255 : 100, 20);
+
return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
@@ -2881,7 +3150,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_intent,
wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
- wpa_s->p2p_pd_before_go_neg);
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40);
return;
}
@@ -3177,6 +3447,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
* parameters or -1 to generate new values (SSID/passphrase)
* @pd: Whether to send Provision Discovery prior to GO Negotiation as an
* interoperability workaround when initiating group formation
+ * @ht40: Start GO with 40 MHz channel width
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -3184,7 +3455,8 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join, int auth,
- int go_intent, int freq, int persistent_id, int pd)
+ int go_intent, int freq, int persistent_id, int pd,
+ int ht40)
{
int force_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
@@ -3216,6 +3488,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_connect_freq = freq;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->p2p_pd_before_go_neg = !!pd;
+ wpa_s->p2p_go_ht40 = !!ht40;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -3447,13 +3720,14 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq)
+ int freq, int ht40)
{
u8 bssid[ETH_ALEN];
int res;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
+ params->ht40 = ht40;
if (freq) {
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
"frequency %d MHz", freq);
@@ -3565,7 +3839,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* i.e., without using Group Owner Negotiation.
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq)
+ int freq, int ht40)
{
struct p2p_go_neg_results params;
unsigned int r;
@@ -3623,7 +3897,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, &params, freq))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
return -1;
if (params.freq &&
!p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
@@ -3690,7 +3964,7 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq)
+ int freq, int ht40)
{
struct p2p_go_neg_results params;
int go = 0;
@@ -3716,7 +3990,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, &params, freq))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
return -1;
params.role_go = 1;
@@ -3955,7 +4229,7 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id)
+ const u8 *dev_id, unsigned int search_delay)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
@@ -3970,7 +4244,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
wpa_supplicant_cancel_sched_scan(wpa_s);
return p2p_find(wpa_s->global->p2p, timeout, type,
- num_req_dev_types, req_dev_types, dev_id);
+ num_req_dev_types, req_dev_types, dev_id,
+ search_delay);
}
@@ -4263,7 +4538,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
}
if (!wpa_s->show_group_started || !ssid)
- return;
+ goto done;
wpa_s->show_group_started = 0;
@@ -4305,6 +4580,19 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
if (network_id < 0)
network_id = ssid->id;
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+
+done:
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after successful connection");
+ p2p_increase_search_delay(
+ wpa_s->global->p2p,
+ wpas_p2p_search_delay(wpa_s));
+ }
+ }
}
@@ -4360,8 +4648,7 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
"group");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT);
}
@@ -4441,8 +4728,8 @@ void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
"session is ending");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION;
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION);
}
}
@@ -4810,7 +5097,8 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_REQUESTED);
break;
}
}
@@ -4831,8 +5119,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
"being available anymore");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE);
}
@@ -4878,10 +5165,7 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
if (wpa_s == NULL)
return -1;
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
- wpas_p2p_group_delete(wpa_s, 0);
-
- return 0;
+ return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED);
}
@@ -4984,13 +5268,14 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpa_s = wpa_s->parent;
offchannel_send_action_done(wpa_s);
if (group_added)
- wpas_p2p_group_delete(group, 1);
+ wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
- wpa_s->p2p_pd_before_go_neg);
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40);
}
@@ -5010,6 +5295,44 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
return 1;
}
+
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
+{
+ const char *rn, *rn2;
+ struct wpa_supplicant *ifs;
+
+ if (wpa_s->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
+ "concurrent operation",
+ P2P_CONCURRENT_SEARCH_DELAY);
+ return P2P_CONCURRENT_SEARCH_DELAY;
+ }
+
+ if (!wpa_s->driver->get_radio_name)
+ return 0;
+ rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ if (rn == NULL || rn[0] == '\0')
+ return 0;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s || !ifs->driver->get_radio_name)
+ continue;
+
+ rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+ if (!rn2 || os_strcmp(rn, rn2) != 0)
+ continue;
+ if (ifs->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
+ "delay due to concurrent operation on "
+ "interface %s",
+ P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
+ return P2P_CONCURRENT_SEARCH_DELAY;
+ }
+ }
+
+ return 0;
+}
+
#ifdef ANDROID_P2P
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
{
@@ -5039,8 +5362,7 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
* P2P connection. So remove the interface */
wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
"concurrent mode frequency conflict");
- iface->removal_reason = P2P_GROUP_REMOVAL_FREQ_CONFLICT;
- wpas_p2p_group_delete(iface, 0);
+ wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
} else {
/* Existing connection has the priority. Disable the newly
* selected network and let the application know about it.
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 5af323f6..bbdd83e7 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -21,7 +21,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join,
int auth, int go_intent, int freq, int persistent_id,
- int pd);
+ int pd, int ht40);
void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration);
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
@@ -32,10 +32,10 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
#endif
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq);
+ int freq, int ht40);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq);
+ int freq, int ht40);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
@@ -57,7 +57,7 @@ enum p2p_discovery_type;
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id);
+ const u8 *dev_id, unsigned int search_delay);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
@@ -90,6 +90,8 @@ u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs);
u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
u8 version, const char *query);
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *role);
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
const u8 *dst, u8 dialog_token,
@@ -149,5 +151,8 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr);
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel);
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 8df21d9c..d8db81fb 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -89,6 +89,9 @@ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
count++;
ssid = ssid->next;
}
+ if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+ wpa_s->conf->auto_interworking)
+ count++;
return count;
}
@@ -138,7 +141,7 @@ static void int_array_concat(int **res, const int *a)
reslen = int_array_len(*res);
alen = int_array_len(a);
- n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
+ n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
if (n == NULL) {
os_free(*res);
*res = NULL;
@@ -385,9 +388,7 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
-static struct wpabuf *
-wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params)
+static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *extra_ie = NULL;
#ifdef CONFIG_WPS
@@ -475,15 +476,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
#ifdef CONFIG_P2P
if (wpas_p2p_in_progress(wpa_s)) {
- if (wpa_s->wpa_state == WPA_SCANNING) {
+ if (wpa_s->sta_scan_pending &&
+ wpas_p2p_in_progress(wpa_s) == 2 &&
+ wpa_s->p2p_cb_on_scan_complete) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
+ "mode scan during P2P search");
+ } else {
wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
"while P2P operation is in progress");
+ wpa_s->sta_scan_pending = 1;
wpa_supplicant_req_scan(wpa_s, 5, 0);
- } else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while "
- "P2P operation is in progress");
+ return;
}
- return;
}
#endif /* CONFIG_P2P */
@@ -642,7 +646,7 @@ ssid_list_set:
#endif /* CONFIG_P2P */
wpa_supplicant_optimize_freqs(wpa_s, &params);
- extra_ie = wpa_supplicant_extra_ies(wpa_s, &params);
+ extra_ie = wpa_supplicant_extra_ies(wpa_s);
#ifdef CONFIG_HS20
if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
@@ -771,7 +775,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
struct wpa_driver_scan_params *scan_params;
enum wpa_states prev_state;
struct wpa_ssid *ssid = NULL;
- struct wpabuf *wps_ie = NULL;
+ struct wpabuf *extra_ie = NULL;
int ret;
unsigned int max_sched_scan_ssids;
int wildcard = 0;
@@ -935,8 +939,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
params.filter_ssids = NULL;
}
- if (wpa_s->wps)
- wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
+ extra_ie = wpa_supplicant_extra_ies(wpa_s);
+ if (extra_ie) {
+ params.extra_ies = wpabuf_head(extra_ie);
+ params.extra_ies_len = wpabuf_len(extra_ie);
+ }
scan_params = &params;
@@ -953,7 +960,7 @@ scan:
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
- wpabuf_free(wps_ie);
+ wpabuf_free(extra_ie);
os_free(params.filter_ssids);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index c7187e43..b09e5f18 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -127,6 +127,15 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
"key management and encryption suites");
return;
}
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+ /*
+ * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+ * use non-WPA since the scan results did not indicate that the
+ * AP is using WPA or WPA2.
+ */
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_s->sme.assoc_req_ie_len = 0;
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -802,7 +811,7 @@ static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
return;
}
- params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
for (count = 0, i = 0; i < mode->num_channels; i++) {
@@ -843,6 +852,8 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
const u8 *ie;
struct wpa_bss *bss = wpa_s->current_bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_hw_modes *hw_mode = NULL;
+ int i;
eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
wpa_s->sme.sched_obss_scan = 0;
@@ -853,9 +864,20 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
ssid->mode != IEEE80211_MODE_INFRA)
return; /* Not using station SME in wpa_supplicant */
- if (!wpa_s->hw.modes ||
- !(wpa_s->hw.modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- return; /* Driver does not support HT40 */
+ if (!wpa_s->hw.modes)
+ return;
+
+ /* only HT caps in 11g mode are relevant */
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ hw_mode = &wpa_s->hw.modes[i];
+ if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ break;
+ }
+
+ /* Driver does not support HT40 for 11g or doesn't have 11g. */
+ if (i == wpa_s->hw.num_modes || !hw_mode ||
+ !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return;
if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
return; /* Not associated on 2.4 GHz band */
@@ -938,9 +960,9 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
sme_check_sa_query_timeout(wpa_s))
return;
- nbuf = os_realloc(wpa_s->sme.sa_query_trans_id,
- (wpa_s->sme.sa_query_count + 1) *
- WLAN_SA_QUERY_TR_ID_LEN);
+ nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
+ wpa_s->sme.sa_query_count + 1,
+ WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (wpa_s->sme.sa_query_count == 0) {
diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c
index 44488588..f60b1821 100644
--- a/wpa_supplicant/tests/test_eap_sim_common.c
+++ b/wpa_supplicant/tests/test_eap_sim_common.c
@@ -28,7 +28,7 @@ static int test_eap_sim_prf(void)
printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w) != 0)) {
+ if (memcmp(w, buf, sizeof(w)) != 0) {
printf("eap_sim_prf failed\n");
return 1;
}
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
new file mode 100644
index 00000000..92ca5360
--- /dev/null
+++ b/wpa_supplicant/wifi_display.c
@@ -0,0 +1,251 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wifi_display.h"
+
+
+int wifi_display_init(struct wpa_global *global)
+{
+ global->wifi_display = 1;
+ return 0;
+}
+
+
+void wifi_display_deinit(struct wpa_global *global)
+{
+ int i;
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ wpabuf_free(global->wfd_subelem[i]);
+ global->wfd_subelem[i] = NULL;
+ }
+}
+
+
+static int wifi_display_update_wfd_ie(struct wpa_global *global)
+{
+ struct wpabuf *ie, *buf;
+ size_t len, plen;
+
+ wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
+
+ if (!global->wifi_display) {
+ wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
+ "include WFD IE");
+ p2p_set_wfd_ie_beacon(global->p2p, NULL);
+ p2p_set_wfd_ie_probe_req(global->p2p, NULL);
+ p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
+ p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
+ p2p_set_wfd_ie_invitation(global->p2p, NULL);
+ p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
+ p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
+ p2p_set_wfd_ie_go_neg(global->p2p, NULL);
+ p2p_set_wfd_dev_info(global->p2p, NULL);
+ p2p_set_wfd_assoc_bssid(global->p2p, NULL);
+ p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
+ return 0;
+ }
+
+ p2p_set_wfd_dev_info(global->p2p,
+ global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ p2p_set_wfd_assoc_bssid(
+ global->p2p,
+ global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
+ p2p_set_wfd_coupled_sink_info(
+ global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+ /*
+ * WFD IE is included in number of management frames. Two different
+ * sets of subelements are included depending on the frame:
+ *
+ * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
+ * Provision Discovery Req:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ *
+ * Probe Request:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Extended Capability]
+ *
+ * Probe Response:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Extended Capability]
+ * [WFD Session Info]
+ *
+ * (Re)Association Response, P2P Invitation Req/Resp,
+ * Provision Discovery Resp:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Session Info]
+ */
+ len = 0;
+ if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_DEVICE_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_ASSOCIATED_BSSID]);
+ if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_COUPLED_SINK]);
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_SESSION_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+ len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+ wpabuf_put_buf(buf, global->wfd_subelem[
+ WFD_SUBELEM_ASSOCIATED_BSSID]);
+ if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
+ p2p_set_wfd_ie_beacon(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
+ ie);
+ p2p_set_wfd_ie_assoc_req(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
+ p2p_set_wfd_ie_go_neg(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+ "Request", ie);
+ p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
+
+ plen = buf->used;
+ if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
+ p2p_set_wfd_ie_probe_req(global->p2p, ie);
+
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
+ p2p_set_wfd_ie_probe_resp(global->p2p, ie);
+
+ /* Remove WFD Extended Capability from buffer */
+ buf->used = plen;
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
+ p2p_set_wfd_ie_invitation(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+ "Response", ie);
+ p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
+
+ wpabuf_free(buf);
+
+ return 0;
+}
+
+
+void wifi_display_enable(struct wpa_global *global, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
+ enabled ? "enabled" : "disabled");
+ global->wifi_display = enabled;
+ wifi_display_update_wfd_ie(global);
+}
+
+
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
+{
+ char *pos;
+ int subelem;
+ size_t len;
+ struct wpabuf *e;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ if (len == 0) {
+ /* Clear subelement */
+ e = NULL;
+ wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
+ } else {
+ e = wpabuf_alloc(1 + len);
+ if (e == NULL)
+ return -1;
+ wpabuf_put_u8(e, subelem);
+ if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+ wpabuf_free(e);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
+ }
+
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = e;
+ wifi_display_update_wfd_ie(global);
+
+ return 0;
+}
+
+
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+ char *buf, size_t buflen)
+{
+ int subelem;
+
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
+ if (global->wfd_subelem[subelem] == NULL)
+ return 0;
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(global->wfd_subelem[subelem]) +
+ 1,
+ wpabuf_len(global->wfd_subelem[subelem]) - 1);
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
new file mode 100644
index 00000000..b75d4f2d
--- /dev/null
+++ b/wpa_supplicant/wifi_display.h
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WIFI_DISPLAY_H
+#define WIFI_DISPLAY_H
+
+int wifi_display_init(struct wpa_global *global);
+void wifi_display_deinit(struct wpa_global *global);
+void wifi_display_enable(struct wpa_global *global, int enabled);
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+ char *buf, size_t buflen);
+
+#endif /* WIFI_DISPLAY_H */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
new file mode 100644
index 00000000..98ce9661
--- /dev/null
+++ b/wpa_supplicant/wnm_sta.c
@@ -0,0 +1,248 @@
+/*
+ * wpa_supplicant - WNM
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "rsn_supp/wpa.h"
+#include "../wpa_supplicant/wpa_supplicant_i.h"
+#include "../wpa_supplicant/driver_i.h"
+
+#define MAX_TFS_IE_LEN 1024
+
+#ifdef CONFIG_IEEE80211V
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
+ u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+ return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
+ const u8 *addr, u8 *buf, u16 *buf_len,
+ enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+ return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.request */
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+ u8 action, u8 intval)
+{
+ struct ieee80211_mgmt *mgmt;
+ int res;
+ size_t len;
+ struct wnm_sleep_element *wnmsleep_ie;
+ u8 *wnmtfs_ie;
+ u8 wnmsleep_ie_len;
+ u16 wnmtfs_ie_len; /* possibly multiple IE(s) */
+ enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
+ WNM_SLEEP_TFS_REQ_IE_NONE;
+
+ /* WNM-Sleep Mode IE */
+ wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+ wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
+ if (wnmsleep_ie == NULL)
+ return -1;
+ wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
+ wnmsleep_ie->len = wnmsleep_ie_len - 2;
+ wnmsleep_ie->action_type = action;
+ wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
+ wnmsleep_ie->intval = intval;
+
+ /* TFS IE(s) */
+ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+ if (wnmtfs_ie == NULL) {
+ os_free(wnmsleep_ie);
+ return -1;
+ }
+ if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
+ tfs_oper)) {
+ wnmtfs_ie_len = 0;
+ os_free(wnmtfs_ie);
+ wnmtfs_ie = NULL;
+ }
+
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+ if (mgmt == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+ "WNM-Sleep Request action frame");
+ return -1;
+ }
+
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
+ wnmsleep_ie_len);
+ /* copy TFS IE here */
+ if (wnmtfs_ie_len > 0) {
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+ wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
+ }
+
+ len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
+ wnmtfs_ie_len;
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
+ "(action=%d, intval=%d)", action, intval);
+
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+
+ return res;
+}
+
+
+static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
+ const u8 *frm, int len)
+{
+ /*
+ * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
+ * WNM-Sleep Mode IE | TFS Response IE
+ */
+ u8 *pos = (u8 *) frm; /* point to action field */
+ u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
+ u8 gtk_len;
+#ifdef CONFIG_IEEE80211W
+ u8 igtk_len;
+#endif /* CONFIG_IEEE80211W */
+ struct wnm_sleep_element *wnmsleep_ie = NULL;
+ /* multiple TFS Resp IE (assuming consecutive) */
+ u8 *tfsresp_ie_start = NULL;
+ u8 *tfsresp_ie_end = NULL;
+ u16 tfsresp_ie_len = 0;
+
+ wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
+ frm[0], frm[1], key_len_total);
+ pos += 4 + key_len_total;
+ while (pos - frm < len) {
+ u8 ie_len = *(pos + 1);
+ if (*pos == WLAN_EID_WNMSLEEP)
+ wnmsleep_ie = (struct wnm_sleep_element *) pos;
+ else if (*pos == WLAN_EID_TFS_RESP) {
+ if (!tfsresp_ie_start)
+ tfsresp_ie_start = pos;
+ tfsresp_ie_end = pos;
+ } else
+ wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+ pos += ie_len + 2;
+ }
+
+ if (!wnmsleep_ie) {
+ wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+ return;
+ }
+
+ if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT) {
+ wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
+ "frame (action=%d, intval=%d)",
+ wnmsleep_ie->action_type, wnmsleep_ie->intval);
+ if (wnmsleep_ie->action_type == 0) {
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
+ wpa_s->bssid, NULL, NULL);
+ /* remove GTK/IGTK ?? */
+
+ /* set the TFS Resp IE(s) */
+ if (tfsresp_ie_start && tfsresp_ie_end &&
+ tfsresp_ie_end - tfsresp_ie_start >= 0) {
+ tfsresp_ie_len = (tfsresp_ie_end +
+ tfsresp_ie_end[1] + 2) -
+ tfsresp_ie_start;
+ wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
+ /*
+ * pass the TFS Resp IE(s) to driver for
+ * processing
+ */
+ if (ieee80211_11_set_tfs_ie(
+ wpa_s, wpa_s->bssid,
+ tfsresp_ie_start,
+ &tfsresp_ie_len,
+ WNM_SLEEP_TFS_RESP_IE_SET))
+ wpa_printf(MSG_DEBUG, "Fail to set "
+ "TFS Resp IE");
+ }
+ } else if (wnmsleep_ie->action_type == 1) {
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,
+ wpa_s->bssid, NULL, NULL);
+ /* Install GTK/IGTK */
+ do {
+ /* point to key data field */
+ u8 *ptr = (u8 *) frm + 1 + 1 + 2;
+ while (ptr < (u8 *) frm + 4 + key_len_total) {
+ if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
+ gtk_len = *(ptr + 4);
+ wpa_wnmsleep_install_key(
+ wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_GTK,
+ ptr);
+ ptr += 13 + gtk_len;
+#ifdef CONFIG_IEEE80211W
+ } else if (*ptr ==
+ WNM_SLEEP_SUBELEM_IGTK) {
+ igtk_len = WPA_IGTK_LEN;
+ wpa_wnmsleep_install_key(
+ wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_IGTK,
+ ptr);
+ ptr += 10 + WPA_IGTK_LEN;
+#endif /* CONFIG_IEEE80211W */
+ } else
+ break; /* skip the loop */
+ }
+ } while(0);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
+ "(action=%d, intval=%d)",
+ wnmsleep_ie->action_type, wnmsleep_ie->intval);
+ if (wnmsleep_ie->action_type == 0)
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
+ wpa_s->bssid, NULL, NULL);
+ else if (wnmsleep_ie->action_type == 1)
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
+ wpa_s->bssid, NULL, NULL);
+ }
+}
+
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+ struct rx_action *action)
+{
+ u8 *pos = (u8 *) action->data; /* point to action field */
+ u8 act = *pos++;
+ /* u8 dialog_token = *pos++; */
+
+ switch (act) {
+ case WNM_SLEEP_MODE_RESP:
+ ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif /* CONFIG_IEEE80211V */
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
new file mode 100644
index 00000000..ba2535b0
--- /dev/null
+++ b/wpa_supplicant/wnm_sta.h
@@ -0,0 +1,21 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_STA_H
+#define WNM_STA_H
+
+struct rx_action;
+struct wpa_supplicant;
+
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+ u8 action, u8 intval);
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+ struct rx_action *action);
+
+#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index bed13dd9..3986b9be 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -95,8 +95,11 @@ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
-static void print_help(void);
+static void print_help(const char *cmd);
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
+static void wpa_cli_close_connection(void);
+static char * wpa_cli_get_default_ifname(void);
+static char ** wpa_list_cmd_list(void);
static void usage(void)
@@ -113,7 +116,7 @@ static void usage(void)
" -B = run a daemon in the background\n"
" default path: " CONFIG_CTRL_IFACE_DIR "\n"
" default interface: first interface found in socket path\n");
- print_help();
+ print_help(NULL);
}
@@ -241,7 +244,7 @@ static char ** cli_txt_list_array(struct dl_list *txt_list)
char **res;
struct cli_txt_entry *e;
- res = os_zalloc((count + 1) * sizeof(char *));
+ res = os_calloc(count + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -364,6 +367,7 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
} else {
printf("Warning: Failed to attach to "
"wpa_supplicant.\n");
+ wpa_cli_close_connection();
return -1;
}
}
@@ -456,6 +460,58 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
}
+static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+ char *argv[])
+{
+ int i, res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos, "%s", cmd);
+ if (res < 0 || res >= end - pos)
+ goto fail;
+ pos += res;
+
+ for (i = 0; i < argc; i++) {
+ res = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (res < 0 || res >= end - pos)
+ goto fail;
+ pos += res;
+ }
+
+ buf[buflen - 1] = '\0';
+ return 0;
+
+fail:
+ printf("Too long command\n");
+ return -1;
+}
+
+
+static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
+ int argc, char *argv[])
+{
+ char buf[256];
+ if (argc < min_args) {
+ printf("Invalid %s command - at least %d argument%s "
+ "required.\n", cmd, min_args,
+ min_args > 1 ? "s are" : " is");
+ return -1;
+ }
+ if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "IFNAME");
+}
+
+
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
@@ -480,14 +536,7 @@ static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int ret;
- if (argc == 0)
- return -1;
- ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]);
- if (ret < 0 || (size_t) ret >= sizeof(cmd))
- return -1;
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
}
@@ -505,11 +554,26 @@ static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- print_help();
+ print_help(argc > 0 ? argv[0] : NULL);
return 0;
}
+static char ** wpa_cli_complete_help(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = wpa_list_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
@@ -577,21 +641,7 @@ static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid GET command: need one argument (variable "
- "name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long GET command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
}
@@ -617,100 +667,34 @@ static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid PREAUTH command: needs one argument "
- "(BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long PREAUTH command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
}
static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid AP_SCAN command: needs one argument (ap_scan "
- "value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long AP_SCAN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
}
static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid SCAN_INTERVAL command: needs one argument "
- "scan_interval value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "SCAN_INTERVAL %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SCAN_INTERVAL command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
}
static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid BSS_EXPIRE_AGE command: needs one argument "
- "(bss_expire_age value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_AGE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long BSS_EXPIRE_AGE command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
}
static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid BSS_EXPIRE_COUNT command: needs one argument "
- "(bss_expire_count value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_COUNT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long BSS_EXPIRE_COUNT command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
}
@@ -734,69 +718,24 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid STKSTART command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long STKSTART command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
}
static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid FT_DS command: needs one argument "
- "(Target AP MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long FT_DS command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
}
static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc == 0) {
- /* Any BSSID */
- return wpa_ctrl_command(ctrl, "WPS_PBC");
- }
-
- /* Specific BSSID */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PBC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
}
static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
printf("Invalid WPS_PIN command: need one or two arguments:\n"
"- BSSID: use 'any' to select any\n"
@@ -805,49 +744,14 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
return -1;
}
- if (argc == 1) {
- /* Use dynamically generated PIN (returned as reply) */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
- }
-
- /* Use hardcoded PIN from a label */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
}
static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1 && argc != 2) {
- printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
- "- PIN to be verified\n");
- return -1;
- }
-
- if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_CHECK_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
}
@@ -861,9 +765,6 @@ static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
#ifdef CONFIG_WPS_OOB
static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 3 && argc != 4) {
printf("Invalid WPS_OOB command: need three or four "
"arguments:\n"
@@ -876,17 +777,7 @@ static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_OOB command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv);
}
#endif /* CONFIG_WPS_OOB */
@@ -895,43 +786,14 @@ static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc >= 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC %s",
- argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC");
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_NFC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
}
static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid WPS_NFC_TOKEN command: need one argument:\n"
- "format: WPS or NDEF\n");
- return -1;
- }
- if (argc >= 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s",
- argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN");
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_NFC_TOKEN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
}
@@ -1023,41 +885,14 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc < 1) {
- printf("Invalid WPS_AP_PIN command: needs at least one "
- "argument\n");
- return -1;
- }
-
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_AP_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
}
static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- if (argc > 0) {
- os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]);
- return wpa_ctrl_command(ctrl, cmd);
- }
- return wpa_ctrl_command(ctrl, "WPS_ER_START");
+ return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
}
@@ -1072,9 +907,6 @@ static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc < 2) {
printf("Invalid WPS_ER_PIN command: need at least two "
"arguments:\n"
@@ -1084,48 +916,20 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
}
static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid WPS_ER_PBC command: need one argument:\n"
- "- UUID: Specify the Enrollee\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_PBC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
}
static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
"- UUID: specify which AP to use\n"
@@ -1133,22 +937,13 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_LEARN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
}
static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_SET_CONFIG command: need two "
"arguments:\n"
@@ -1157,13 +952,7 @@ static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_SET_CONFIG %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_SET_CONFIG command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
}
@@ -1222,9 +1011,6 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
"arguments:\n"
@@ -1233,53 +1019,20 @@ static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_NFC_CONFIG_TOKEN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_NFC_CONFIG_TOKEN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
}
#endif /* CONFIG_WPS_NFC */
static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid IBSS_RSN command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long IBSS_RSN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
}
static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid LEVEL command: needs one argument (debug "
- "level)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long LEVEL command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
}
@@ -1484,85 +1237,25 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
if (argc < 2) {
printf("Invalid BSSID command: needs two arguments (network "
"id and BSSID)\n");
return -1;
}
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "BSSID");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BSSID command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BSSID command.\n");
- return -1;
- }
- pos += ret;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
}
static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "BLACKLIST");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BLACKLIST command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BLACKLIST command.\n");
- return -1;
- }
- pos += ret;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
}
static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "LOG_LEVEL");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long LOG_LEVEL command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long LOG_LEVEL command.\n");
- return -1;
- }
- pos += ret;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
}
@@ -1576,68 +1269,21 @@ static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid SELECT_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
}
static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid ENABLE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
}
static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid DISABLE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
}
@@ -1651,21 +1297,7 @@ static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid REMOVE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
}
@@ -1693,9 +1325,6 @@ static void wpa_cli_show_network_variables(void)
static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
wpa_cli_show_network_variables();
return 0;
@@ -1707,22 +1336,13 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
- argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET_NETWORK command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
}
static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
wpa_cli_show_network_variables();
return 0;
@@ -1734,13 +1354,7 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long GET_NETWORK command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
}
@@ -1760,42 +1374,19 @@ static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid REMOVE_CRED command: needs one argument "
- "(cred id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
}
static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 3) {
printf("Invalid SET_CRED command: needs three arguments\n"
"(cred id, variable name, and value)\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "SET_CRED %s %s %s",
- argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET_CRED command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
}
@@ -1835,24 +1426,7 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[64];
- int res;
-
- if (argc < 1) {
- printf("Invalid BSS command: need at least one argument"
- "(index or BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "BSS %s%s%s%s%s", argv[0],
- argc > 1 ? " " : "", argc > 1 ? argv[1] : "",
- argc > 2 ? " " : "", argc > 2 ? argv[2] : "");
-
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
}
@@ -1874,9 +1448,6 @@ static char ** wpa_cli_complete_bss(const char *str, int pos)
static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[64];
- int res;
-
if (argc < 1 || argc > 2) {
printf("Invalid GET_CAPABILITY command: need either one or "
"two arguments\n");
@@ -1889,13 +1460,7 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
- (argc == 2) ? " strict" : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
}
@@ -1975,20 +1540,7 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid INTERFACE_REMOVE command: needs one argument "
- "(interface name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
}
@@ -2002,14 +1554,7 @@ static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
#ifdef CONFIG_AP
static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char buf[64];
- if (argc != 1) {
- printf("Invalid 'sta' command - exactly one argument, STA "
- "address, is required.\n");
- return -1;
- }
- os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
}
@@ -2066,36 +1611,14 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char buf[64];
- if (argc < 1) {
- printf("Invalid 'deauthenticate' command - exactly one "
- "argument, STA address, is required.\n");
- return -1;
- }
- if (argc > 1)
- os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
- argv[0], argv[1]);
- else
- os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
}
static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char buf[64];
- if (argc < 1) {
- printf("Invalid 'disassociate' command - exactly one "
- "argument, STA address, is required.\n");
- return -1;
- }
- if (argc > 1)
- os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
- argv[0], argv[1]);
- else
- os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
}
#endif /* CONFIG_AP */
@@ -2120,21 +1643,7 @@ static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid ROAM command: needs one argument "
- "(target AP's BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long ROAM command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
}
@@ -2142,24 +1651,36 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[128];
- int res;
+ return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
+}
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_FIND");
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
+{
+ char **res = NULL;
+ int arg = get_cmd_arg_num(str, pos);
+
+ res = os_calloc(6, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ res[0] = os_strdup("type=social");
+ if (res[0] == NULL) {
+ os_free(res);
+ return NULL;
+ }
+ res[1] = os_strdup("type=progressive");
+ if (res[1] == NULL)
+ return res;
+ res[2] = os_strdup("delay=");
+ if (res[2] == NULL)
+ return res;
+ res[3] = os_strdup("dev_id=");
+ if (res[3] == NULL)
+ return res;
+ if (arg == 1)
+ res[4] = os_strdup("[timeout]");
+
+ return res;
}
@@ -2173,40 +1694,7 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc < 2) {
- printf("Invalid P2P_CONNECT command: needs at least two "
- "arguments (address and pbc/PIN)\n");
- return -1;
- }
-#ifdef ANDROID_P2P
- if (argc > 5)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_CONNECT %s %s %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3],
- argv[4], argv[5]);
- else
-#endif
- if (argc > 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_CONNECT %s %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3],
- argv[4]);
- else if (argc > 3)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
}
@@ -2228,37 +1716,14 @@ static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_LISTEN");
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_LISTEN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_GROUP_REMOVE command: needs one argument "
- "(interface name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
}
@@ -2280,31 +1745,13 @@ static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_GROUP_ADD");
-
- if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
if (argc != 2 && argc != 3) {
printf("Invalid P2P_PROV_DISC command: needs at least "
"two arguments, address and config method\n"
@@ -2312,16 +1759,7 @@ static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
}
@@ -2336,7 +1774,6 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[4096];
- int res;
if (argc != 2 && argc != 4) {
printf("Invalid P2P_SERV_DISC_REQ command: needs two "
@@ -2346,16 +1783,8 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERV_DISC_REQ %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
return -1;
- cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -2363,21 +1792,7 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_SERV_DISC_CANCEL_REQ command: needs one "
- "argument (pending request identifier)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_CANCEL_REQ %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
}
@@ -2412,21 +1827,7 @@ static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_SERV_DISC_EXTERNAL command: needs one "
- "argument (external processing: 0/1)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_EXTERNAL %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
}
@@ -2494,60 +1895,20 @@ static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_REJECT command: needs one argument "
- "(peer address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_REJECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc < 1) {
- printf("Invalid P2P_INVITE command: needs at least one "
- "argument\n");
- return -1;
- }
-
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char buf[64];
- if (argc != 1) {
- printf("Invalid 'p2p_peer' command - exactly one argument, "
- "P2P peer device address, is required.\n");
- return -1;
- }
- os_snprintf(buf, sizeof(buf), "P2P_PEER %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
}
@@ -2623,20 +1984,7 @@ static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc != 2) {
- printf("Invalid P2P_SET command: needs two arguments (field, "
- "value)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SET %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
}
@@ -2656,48 +2004,58 @@ static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid P2P_UNAUTHORIZE command: needs one argument "
- "(peer address)\n");
+
+static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc != 0 && argc != 2 && argc != 4) {
+ printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
+ "(preferred duration, interval; in microsecods).\n"
+ "Optional second pair can be used to provide "
+ "acceptable values.\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "P2P_UNAUTHORIZE %s", argv[0]);
+ return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
+}
- if (res < 0 || (size_t) res >= sizeof(cmd))
+
+static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc != 0 && argc != 2) {
+ printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
+ "(availability period, availability interval; in "
+ "millisecods).\n"
+ "Extended Listen Timing can be cancelled with this "
+ "command when used without parameters.\n");
return -1;
+ }
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
}
+#endif /* CONFIG_P2P */
-static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+#ifdef CONFIG_WIFI_DISPLAY
+
+static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
char cmd[100];
int res;
- if (argc != 0 && argc != 2 && argc != 4) {
- printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
- "(preferred duration, interval; in microsecods).\n"
- "Optional second pair can be used to provide "
- "acceptable values.\n");
+ if (argc != 1 && argc != 2) {
+ printf("Invalid WFD_SUBELEM_SET command: needs one or two "
+ "arguments (subelem, hexdump)\n");
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_PRESENCE_REQ %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ");
+ res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
+ argv[0], argc > 1 ? argv[1] : "");
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
@@ -2705,33 +2063,26 @@ static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
}
-static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
char cmd[100];
int res;
- if (argc != 0 && argc != 2) {
- printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
- "(availability period, availability interval; in "
- "millisecods).\n"
- "Extended Listen Timing can be cancelled with this "
- "command when used without parameters.\n");
+ if (argc != 1) {
+ printf("Invalid WFD_SUBELEM_GET command: needs one "
+ "argument (subelem)\n");
return -1;
}
- if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN");
+ res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
+ argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
-
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
@@ -2752,58 +2103,34 @@ static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
}
static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
+}
- if (argc != 1) {
- printf("Invalid INTERWORKING_CONNECT commands: needs one "
- "argument (BSSID)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
}
-static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
+}
- if (argc != 2) {
- printf("Invalid ANQP_GET command: needs two arguments "
- "(addr and info id list)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
}
#endif /* CONFIG_INTERWORKING */
@@ -2813,21 +2140,7 @@ static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc != 2) {
- printf("Invalid HS20_ANQP_GET command: needs two arguments "
- "(addr and subtype list)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "HS20_ANQP_GET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
}
@@ -2835,7 +2148,6 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[512];
- int res;
if (argc == 0) {
printf("Command needs one or two arguments (dst mac addr and "
@@ -2843,18 +2155,9 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (argc == 1)
- res = os_snprintf(cmd, sizeof(cmd),
- "HS20_GET_NAI_HOME_REALM_LIST %s",
- argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd),
- "HS20_GET_NAI_HOME_REALM_LIST %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long command.\n");
+ if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
+ argc, argv) < 0)
return -1;
- }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -2865,83 +2168,28 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid STA_AUTOCONNECT command: needs one argument "
- "(0/1 = disable/enable automatic reconnection)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "STA_AUTOCONNECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long STA_AUTOCONNECT command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_DISCOVER command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_DISCOVER %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_DISCOVER command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_SETUP command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_SETUP %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_SETUP command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_TEARDOWN command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_TEARDOWN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
}
@@ -2970,24 +2218,23 @@ static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0)
return wpa_ctrl_command(ctrl, "AUTOSCAN ");
- res = os_snprintf(cmd, sizeof(cmd), "AUTOSCAN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long AUTOSCAN command.\n");
- return -1;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
}
#endif /* CONFIG_AUTOSCAN */
+static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc == 0)
+ return -1;
+ return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
#ifdef ANDROID
static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
@@ -3009,6 +2256,7 @@ static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
#endif
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3017,401 +2265,433 @@ enum wpa_cli_cmd_flags {
struct wpa_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+ char ** (*completion)(const char *str, int pos);
enum wpa_cli_cmd_flags flags;
const char *usage;
};
static struct wpa_cli_cmd wpa_cli_commands[] = {
- { "status", wpa_cli_cmd_status,
+ { "status", wpa_cli_cmd_status, NULL,
cli_cmd_flag_none,
"[verbose] = get current WPA/EAPOL/EAP status" },
- { "ping", wpa_cli_cmd_ping,
+ { "ifname", wpa_cli_cmd_ifname, NULL,
+ cli_cmd_flag_none,
+ "= get current interface name" },
+ { "ping", wpa_cli_cmd_ping, NULL,
cli_cmd_flag_none,
"= pings wpa_supplicant" },
- { "relog", wpa_cli_cmd_relog,
+ { "relog", wpa_cli_cmd_relog, NULL,
cli_cmd_flag_none,
"= re-open log-file (allow rolling logs)" },
- { "note", wpa_cli_cmd_note,
+ { "note", wpa_cli_cmd_note, NULL,
cli_cmd_flag_none,
"<text> = add a note to wpa_supplicant debug log" },
- { "mib", wpa_cli_cmd_mib,
+ { "mib", wpa_cli_cmd_mib, NULL,
cli_cmd_flag_none,
"= get MIB variables (dot1x, dot11)" },
- { "help", wpa_cli_cmd_help,
+ { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
cli_cmd_flag_none,
- "= show this usage help" },
- { "interface", wpa_cli_cmd_interface,
+ "[command] = show usage help" },
+ { "interface", wpa_cli_cmd_interface, NULL,
cli_cmd_flag_none,
"[ifname] = show interfaces/select interface" },
- { "level", wpa_cli_cmd_level,
+ { "level", wpa_cli_cmd_level, NULL,
cli_cmd_flag_none,
"<debug level> = change debug level" },
- { "license", wpa_cli_cmd_license,
+ { "license", wpa_cli_cmd_license, NULL,
cli_cmd_flag_none,
"= show full wpa_cli license" },
- { "quit", wpa_cli_cmd_quit,
+ { "quit", wpa_cli_cmd_quit, NULL,
cli_cmd_flag_none,
"= exit wpa_cli" },
- { "set", wpa_cli_cmd_set,
+ { "set", wpa_cli_cmd_set, NULL,
cli_cmd_flag_none,
"= set variables (shows list of variables when run without "
"arguments)" },
- { "get", wpa_cli_cmd_get,
+ { "get", wpa_cli_cmd_get, NULL,
cli_cmd_flag_none,
"<name> = get information" },
- { "logon", wpa_cli_cmd_logon,
+ { "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
- { "logoff", wpa_cli_cmd_logoff,
+ { "logoff", wpa_cli_cmd_logoff, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logoff" },
- { "pmksa", wpa_cli_cmd_pmksa,
+ { "pmksa", wpa_cli_cmd_pmksa, NULL,
cli_cmd_flag_none,
"= show PMKSA cache" },
- { "reassociate", wpa_cli_cmd_reassociate,
+ { "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
- { "preauthenticate", wpa_cli_cmd_preauthenticate,
+ { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
- { "identity", wpa_cli_cmd_identity,
+ { "identity", wpa_cli_cmd_identity, NULL,
cli_cmd_flag_none,
"<network id> <identity> = configure identity for an SSID" },
- { "password", wpa_cli_cmd_password,
+ { "password", wpa_cli_cmd_password, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = configure password for an SSID" },
- { "new_password", wpa_cli_cmd_new_password,
+ { "new_password", wpa_cli_cmd_new_password, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = change password for an SSID" },
- { "pin", wpa_cli_cmd_pin,
+ { "pin", wpa_cli_cmd_pin, NULL,
cli_cmd_flag_sensitive,
"<network id> <pin> = configure pin for an SSID" },
- { "otp", wpa_cli_cmd_otp,
+ { "otp", wpa_cli_cmd_otp, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
- { "passphrase", wpa_cli_cmd_passphrase,
+ { "passphrase", wpa_cli_cmd_passphrase, NULL,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
- { "bssid", wpa_cli_cmd_bssid,
+ { "bssid", wpa_cli_cmd_bssid, NULL,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
- { "blacklist", wpa_cli_cmd_blacklist,
+ { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = add a BSSID to the blacklist\n"
"blacklist clear = clear the blacklist\n"
"blacklist = display the blacklist" },
- { "log_level", wpa_cli_cmd_log_level,
+ { "log_level", wpa_cli_cmd_log_level, NULL,
cli_cmd_flag_none,
"<level> [<timestamp>] = update the log level/timestamp\n"
"log_level = display the current log level and log options" },
- { "list_networks", wpa_cli_cmd_list_networks,
+ { "list_networks", wpa_cli_cmd_list_networks, NULL,
cli_cmd_flag_none,
"= list configured networks" },
- { "select_network", wpa_cli_cmd_select_network,
+ { "select_network", wpa_cli_cmd_select_network, NULL,
cli_cmd_flag_none,
"<network id> = select a network (disable others)" },
- { "enable_network", wpa_cli_cmd_enable_network,
+ { "enable_network", wpa_cli_cmd_enable_network, NULL,
cli_cmd_flag_none,
"<network id> = enable a network" },
- { "disable_network", wpa_cli_cmd_disable_network,
+ { "disable_network", wpa_cli_cmd_disable_network, NULL,
cli_cmd_flag_none,
"<network id> = disable a network" },
- { "add_network", wpa_cli_cmd_add_network,
+ { "add_network", wpa_cli_cmd_add_network, NULL,
cli_cmd_flag_none,
"= add a network" },
- { "remove_network", wpa_cli_cmd_remove_network,
+ { "remove_network", wpa_cli_cmd_remove_network, NULL,
cli_cmd_flag_none,
"<network id> = remove a network" },
- { "set_network", wpa_cli_cmd_set_network,
+ { "set_network", wpa_cli_cmd_set_network, NULL,
cli_cmd_flag_sensitive,
"<network id> <variable> <value> = set network variables (shows\n"
" list of variables when run without arguments)" },
- { "get_network", wpa_cli_cmd_get_network,
+ { "get_network", wpa_cli_cmd_get_network, NULL,
cli_cmd_flag_none,
"<network id> <variable> = get network variables" },
- { "list_creds", wpa_cli_cmd_list_creds,
+ { "list_creds", wpa_cli_cmd_list_creds, NULL,
cli_cmd_flag_none,
"= list configured credentials" },
- { "add_cred", wpa_cli_cmd_add_cred,
+ { "add_cred", wpa_cli_cmd_add_cred, NULL,
cli_cmd_flag_none,
"= add a credential" },
- { "remove_cred", wpa_cli_cmd_remove_cred,
+ { "remove_cred", wpa_cli_cmd_remove_cred, NULL,
cli_cmd_flag_none,
"<cred id> = remove a credential" },
- { "set_cred", wpa_cli_cmd_set_cred,
+ { "set_cred", wpa_cli_cmd_set_cred, NULL,
cli_cmd_flag_sensitive,
"<cred id> <variable> <value> = set credential variables" },
- { "save_config", wpa_cli_cmd_save_config,
+ { "save_config", wpa_cli_cmd_save_config, NULL,
cli_cmd_flag_none,
"= save the current configuration" },
- { "disconnect", wpa_cli_cmd_disconnect,
+ { "disconnect", wpa_cli_cmd_disconnect, NULL,
cli_cmd_flag_none,
"= disconnect and wait for reassociate/reconnect command before\n"
" connecting" },
- { "reconnect", wpa_cli_cmd_reconnect,
+ { "reconnect", wpa_cli_cmd_reconnect, NULL,
cli_cmd_flag_none,
"= like reassociate, but only takes effect if already disconnected"
},
- { "scan", wpa_cli_cmd_scan,
+ { "scan", wpa_cli_cmd_scan, NULL,
cli_cmd_flag_none,
"= request new BSS scan" },
- { "scan_results", wpa_cli_cmd_scan_results,
+ { "scan_results", wpa_cli_cmd_scan_results, NULL,
cli_cmd_flag_none,
"= get latest scan results" },
- { "bss", wpa_cli_cmd_bss,
+ { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
- { "get_capability", wpa_cli_cmd_get_capability,
+ { "get_capability", wpa_cli_cmd_get_capability, NULL,
cli_cmd_flag_none,
- "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels>\n"
- " = get capabilities" },
- { "reconfigure", wpa_cli_cmd_reconfigure,
+ "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
+ "= get capabilies" },
+ { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
cli_cmd_flag_none,
"= force wpa_supplicant to re-read its configuration file" },
- { "terminate", wpa_cli_cmd_terminate,
+ { "terminate", wpa_cli_cmd_terminate, NULL,
cli_cmd_flag_none,
"= terminate wpa_supplicant" },
- { "interface_add", wpa_cli_cmd_interface_add,
+ { "interface_add", wpa_cli_cmd_interface_add, NULL,
cli_cmd_flag_none,
"<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
" <bridge_name> = adds new interface, all parameters but <ifname>\n"
" are optional" },
- { "interface_remove", wpa_cli_cmd_interface_remove,
+ { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
cli_cmd_flag_none,
"<ifname> = removes the interface" },
- { "interface_list", wpa_cli_cmd_interface_list,
+ { "interface_list", wpa_cli_cmd_interface_list, NULL,
cli_cmd_flag_none,
"= list available interfaces" },
- { "ap_scan", wpa_cli_cmd_ap_scan,
+ { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
cli_cmd_flag_none,
"<value> = set ap_scan parameter" },
- { "scan_interval", wpa_cli_cmd_scan_interval,
+ { "scan_interval", wpa_cli_cmd_scan_interval, NULL,
cli_cmd_flag_none,
"<value> = set scan_interval parameter (in seconds)" },
- { "bss_expire_age", wpa_cli_cmd_bss_expire_age,
+ { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
cli_cmd_flag_none,
"<value> = set BSS expiration age parameter" },
- { "bss_expire_count", wpa_cli_cmd_bss_expire_count,
+ { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
cli_cmd_flag_none,
"<value> = set BSS expiration scan count parameter" },
- { "bss_flush", wpa_cli_cmd_bss_flush,
+ { "bss_flush", wpa_cli_cmd_bss_flush, NULL,
cli_cmd_flag_none,
"<value> = set BSS flush age (0 by default)" },
- { "stkstart", wpa_cli_cmd_stkstart,
+ { "stkstart", wpa_cli_cmd_stkstart, NULL,
cli_cmd_flag_none,
"<addr> = request STK negotiation with <addr>" },
- { "ft_ds", wpa_cli_cmd_ft_ds,
+ { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = request over-the-DS FT with <addr>" },
- { "wps_pbc", wpa_cli_cmd_wps_pbc,
+ { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
- { "wps_pin", wpa_cli_cmd_wps_pin,
+ { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
"<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
"hardcoded)" },
- { "wps_check_pin", wpa_cli_cmd_wps_check_pin,
+ { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
cli_cmd_flag_sensitive,
"<PIN> = verify PIN checksum" },
- { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
+ { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
"Cancels the pending WPS operation" },
#ifdef CONFIG_WPS_OOB
- { "wps_oob", wpa_cli_cmd_wps_oob,
+ { "wps_oob", wpa_cli_cmd_wps_oob, NULL,
cli_cmd_flag_sensitive,
"<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
#endif /* CONFIG_WPS_OOB */
#ifdef CONFIG_WPS_NFC
- { "wps_nfc", wpa_cli_cmd_wps_nfc,
+ { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: NFC" },
- { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token,
+ { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
cli_cmd_flag_none,
"<WPS|NDEF> = create password token" },
- { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read,
+ { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
cli_cmd_flag_sensitive,
"<hexdump of payload> = report read NFC tag with WPS data" },
#endif /* CONFIG_WPS_NFC */
- { "wps_reg", wpa_cli_cmd_wps_reg,
+ { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
- { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
+ { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
cli_cmd_flag_sensitive,
"[params..] = enable/disable AP PIN" },
- { "wps_er_start", wpa_cli_cmd_wps_er_start,
+ { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
cli_cmd_flag_none,
"[IP address] = start Wi-Fi Protected Setup External Registrar" },
- { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
+ { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
cli_cmd_flag_none,
"= stop Wi-Fi Protected Setup External Registrar" },
- { "wps_er_pin", wpa_cli_cmd_wps_er_pin,
+ { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
- { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
+ { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
cli_cmd_flag_none,
"<UUID> = accept an Enrollee PBC using External Registrar" },
- { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
+ { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = learn AP configuration" },
- { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config,
+ { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
cli_cmd_flag_none,
"<UUID> <network id> = set AP configuration for enrolling" },
- { "wps_er_config", wpa_cli_cmd_wps_er_config,
+ { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
#ifdef CONFIG_WPS_NFC
- { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token,
+ { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
cli_cmd_flag_none,
"<WPS/NDEF> <UUID> = build NFC configuration token" },
#endif /* CONFIG_WPS_NFC */
- { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
+ { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
#ifdef CONFIG_AP
- { "sta", wpa_cli_cmd_sta,
+ { "sta", wpa_cli_cmd_sta, NULL,
cli_cmd_flag_none,
"<addr> = get information about an associated station (AP)" },
- { "all_sta", wpa_cli_cmd_all_sta,
+ { "all_sta", wpa_cli_cmd_all_sta, NULL,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
- { "deauthenticate", wpa_cli_cmd_deauthenticate,
+ { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
cli_cmd_flag_none,
"<addr> = deauthenticate a station" },
- { "disassociate", wpa_cli_cmd_disassociate,
+ { "disassociate", wpa_cli_cmd_disassociate, NULL,
cli_cmd_flag_none,
"<addr> = disassociate a station" },
#endif /* CONFIG_AP */
- { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
+ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
- { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
+ { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
"= notification of resume/thaw" },
- { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
+ { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
"= drop SA without deauth/disassoc (test command)" },
- { "roam", wpa_cli_cmd_roam,
+ { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
#ifdef CONFIG_P2P
- { "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
+ { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
+ cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
- { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, cli_cmd_flag_none,
+ { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
"= stop P2P Devices search" },
- { "p2p_connect", wpa_cli_cmd_p2p_connect, cli_cmd_flag_none,
- "<addr> <\"pbc\"|PIN> = connect to a P2P Devices" },
- { "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none,
+ { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
+ cli_cmd_flag_none,
+ "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
+ { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
"[timeout] = listen for P2P Devices for up-to timeout seconds" },
- { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none,
+ { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
+ wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
"<ifname> = remove P2P group interface (terminate group if GO)" },
- { "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none,
- "= add a new P2P group (local end as GO)" },
- { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
+ { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
+ "[ht40] = add a new P2P group (local end as GO)" },
+ { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
- { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,
+ { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
cli_cmd_flag_none,
"= get the passphrase for a group (GO only)" },
{ "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
- cli_cmd_flag_none,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <TLVs> = schedule service discovery request" },
{ "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
- cli_cmd_flag_none,
+ NULL, cli_cmd_flag_none,
"<id> = cancel pending service discovery request" },
- { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
+ { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
cli_cmd_flag_none,
"<freq> <addr> <dialog token> <TLVs> = service discovery response" },
- { "p2p_service_update", wpa_cli_cmd_p2p_service_update,
+ { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
cli_cmd_flag_none,
"= indicate change in local services" },
- { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external,
+ { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
cli_cmd_flag_none,
"<external> = set external processing of service discovery" },
- { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush,
+ { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
cli_cmd_flag_none,
"= remove all stored service entries" },
- { "p2p_service_add", wpa_cli_cmd_p2p_service_add,
+ { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> <response|service> = add a local "
"service" },
- { "p2p_service_del", wpa_cli_cmd_p2p_service_del,
+ { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> [|service] = remove a local "
"service" },
- { "p2p_reject", wpa_cli_cmd_p2p_reject,
+ { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
cli_cmd_flag_none,
"<addr> = reject connection attempts from a specific peer" },
- { "p2p_invite", wpa_cli_cmd_p2p_invite,
+ { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
cli_cmd_flag_none,
"<cmd> [peer=addr] = invite peer" },
- { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
+ { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
"[discovered] = list known (optionally, only fully discovered) P2P "
"peers" },
- { "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none,
+ { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
+ cli_cmd_flag_none,
"<address> = show information about known P2P peer" },
- { "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none,
+ { "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none,
"<field> <value> = set a P2P parameter" },
- { "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none,
+ { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
"= flush P2P state" },
- { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
+ { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
"= cancel P2P group formation" },
- { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
+ { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<address> = unauthorize a peer" },
- { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none,
+ { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
+ cli_cmd_flag_none,
"[<duration> <interval>] [<duration> <interval>] = request GO "
"presence" },
- { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
+ { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
+ cli_cmd_flag_none,
"[<period> <interval>] = set extended listen timing" },
#endif /* CONFIG_P2P */
-
+#ifdef CONFIG_WIFI_DISPLAY
+ { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
+ cli_cmd_flag_none,
+ "<subelem> [contents] = set Wi-Fi Display subelement" },
+ { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
+ cli_cmd_flag_none,
+ "<subelem> = get Wi-Fi Display subelement" },
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
- { "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
+ { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
"= fetch ANQP information for all APs" },
- { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
+ { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
+ cli_cmd_flag_none,
"= stop fetch_anqp operation" },
- { "interworking_select", wpa_cli_cmd_interworking_select,
+ { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
cli_cmd_flag_none,
"[auto] = perform Interworking network selection" },
{ "interworking_connect", wpa_cli_cmd_interworking_connect,
- cli_cmd_flag_none,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
- { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+ { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
+ { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "<addr> <AdvProtoID> [QueryReq] = GAS request" },
+ { "gas_response_get", wpa_cli_cmd_gas_response_get,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
+ "<addr> <dialog token> [start,len] = Fetch last GAS response" },
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
- { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, cli_cmd_flag_none,
+ { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
"<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
},
{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
- cli_cmd_flag_none,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
"<addr> <home realm> = get HS20 nai home realm list" },
#endif /* CONFIG_HS20 */
- { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
+ { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
+ cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
- { "tdls_discover", wpa_cli_cmd_tdls_discover,
+ { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
cli_cmd_flag_none,
"<addr> = request TDLS discovery with <addr>" },
- { "tdls_setup", wpa_cli_cmd_tdls_setup,
+ { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
cli_cmd_flag_none,
"<addr> = request TDLS setup with <addr>" },
- { "tdls_teardown", wpa_cli_cmd_tdls_teardown,
+ { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
- { "signal_poll", wpa_cli_cmd_signal_poll,
+ { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
- { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll,
+ { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
cli_cmd_flag_none,
"= get TX/RX packet counters" },
- { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+ { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
+ cli_cmd_flag_none,
"= trigger IEEE 802.1X/EAPOL reauthentication" },
#ifdef CONFIG_AUTOSCAN
- { "autoscan", wpa_cli_cmd_autoscan, cli_cmd_flag_none,
+ { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
"[params] = Set or unset (if none) autoscan parameters" },
#endif /* CONFIG_AUTOSCAN */
+ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
+ "<params..> = Sent unprocessed command" },
#ifdef ANDROID
- { "driver", wpa_cli_cmd_driver,
+ { "driver", wpa_cli_cmd_driver, NULL,
cli_cmd_flag_none,
"<command> = driver private commands" },
#endif
- { NULL, NULL, cli_cmd_flag_none, NULL }
+ { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3433,12 +2713,14 @@ static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
}
-static void print_help(void)
+static void print_help(const char *cmd)
{
int n;
printf("commands:\n");
- for (n = 0; wpa_cli_commands[n].cmd; n++)
- print_cmd_help(&wpa_cli_commands[n], " ");
+ for (n = 0; wpa_cli_commands[n].cmd; n++) {
+ if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
+ print_cmd_help(&wpa_cli_commands[n], " ");
+ }
}
@@ -3469,7 +2751,7 @@ static char ** wpa_list_cmd_list(void)
int i, count;
count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
- res = os_zalloc(count * sizeof(char *));
+ res = os_calloc(count, sizeof(char *));
if (res == NULL)
return NULL;
@@ -3488,19 +2770,11 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
{
int i;
- if (os_strcasecmp(cmd, "bss") == 0)
- return wpa_cli_complete_bss(str, pos);
-#ifdef CONFIG_P2P
- if (os_strcasecmp(cmd, "p2p_connect") == 0)
- return wpa_cli_complete_p2p_connect(str, pos);
- if (os_strcasecmp(cmd, "p2p_peer") == 0)
- return wpa_cli_complete_p2p_peer(str, pos);
- if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
- return wpa_cli_complete_p2p_group_remove(str, pos);
-#endif /* CONFIG_P2P */
-
for (i = 0; wpa_cli_commands[i].cmd; i++) {
if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
+ if (wpa_cli_commands[i].completion)
+ return wpa_cli_commands[i].completion(str,
+ pos);
edit_clear_line();
printf("\r%s\n", wpa_cli_commands[i].usage);
edit_redraw();
@@ -3711,7 +2985,14 @@ static void wpa_cli_action_cb(char *msg, size_t len)
static void wpa_cli_reconnect(void)
{
wpa_cli_close_connection();
- wpa_cli_open_connection(ctrl_ifname, 1);
+ if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+ return;
+
+ if (interactive) {
+ edit_clear_line();
+ printf("\rConnection to wpa_supplicant re-established\n");
+ edit_redraw();
+ }
}
@@ -3783,6 +3064,33 @@ static void cli_event(const char *str)
}
+static int check_terminating(const char *msg)
+{
+ const char *pos = msg;
+
+ if (*pos == '<') {
+ /* skip priority */
+ pos = os_strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+ edit_clear_line();
+ printf("\rConnection to wpa_supplicant lost - trying to "
+ "reconnect\n");
+ edit_redraw();
+ wpa_cli_attached = 0;
+ wpa_cli_close_connection();
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
{
if (ctrl_conn == NULL) {
@@ -3803,6 +3111,9 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
printf("\r%s\n", buf);
edit_redraw();
}
+
+ if (interactive && check_terminating(buf) > 0)
+ return;
}
} else {
printf("Could not read pending message.\n");
@@ -3862,12 +3173,6 @@ static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
}
-static void wpa_cli_eloop_terminate(int sig, void *signal_ctx)
-{
- eloop_terminate();
-}
-
-
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
wpa_cli_recv_pending(mon_conn, 0);
@@ -3890,11 +3195,18 @@ static void wpa_cli_edit_eof_cb(void *ctx)
}
-static void wpa_cli_interactive(void)
+static int warning_displayed = 0;
+static char *hfile = NULL;
+static int edit_started = 0;
+
+static void start_edit(void)
{
- char *home, *hfile = NULL;
+ char *home;
+ char *ps = NULL;
- printf("\nInteractive mode\n\n");
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
home = getenv("HOME");
if (home) {
@@ -3905,17 +3217,52 @@ static void wpa_cli_interactive(void)
os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
}
- eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL);
- edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
- wpa_cli_edit_completion_cb, NULL, hfile);
+ if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
+ wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
+ eloop_terminate();
+ return;
+ }
+
+ edit_started = 1;
eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+}
+
+
+static void try_connection(void *eloop_ctx, void *timeout_ctx)
+{
+ if (ctrl_ifname == NULL)
+ ctrl_ifname = wpa_cli_get_default_ifname();
+
+ if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+ if (!warning_displayed) {
+ printf("Could not connect to wpa_supplicant: "
+ "%s - re-trying\n", ctrl_ifname);
+ warning_displayed = 1;
+ }
+ eloop_register_timeout(1, 0, try_connection, NULL, NULL);
+ return;
+ }
+
+ if (warning_displayed)
+ printf("Connection established.\n");
+ start_edit();
+}
+
+
+static void wpa_cli_interactive(void)
+{
+ printf("\nInteractive mode\n\n");
+
+ eloop_register_timeout(0, 0, try_connection, NULL, NULL);
eloop_run();
+ eloop_cancel_timeout(try_connection, NULL, NULL);
cli_txt_list_flush(&p2p_peers);
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
- edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
+ if (edit_started)
+ edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
os_free(hfile);
eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
wpa_cli_close_connection();
@@ -3974,10 +3321,10 @@ static void wpa_cli_cleanup(void)
os_program_deinit();
}
-static void wpa_cli_terminate(int sig)
+
+static void wpa_cli_terminate(int sig, void *ctx)
{
- wpa_cli_cleanup();
- exit(0);
+ eloop_terminate();
}
@@ -4051,7 +3398,6 @@ static char * wpa_cli_get_default_ifname(void)
int main(int argc, char *argv[])
{
- int warning_displayed = 0;
int c;
int daemonize = 0;
int ret = 0;
@@ -4121,30 +3467,13 @@ int main(int argc, char *argv[])
}
}
-#ifndef _WIN32_WCE
- signal(SIGINT, wpa_cli_terminate);
- signal(SIGTERM, wpa_cli_terminate);
-#endif /* _WIN32_WCE */
+ eloop_register_signal_terminate(wpa_cli_terminate, NULL);
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
if (interactive) {
- for (; !global;) {
- if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
- if (warning_displayed)
- printf("Connection established.\n");
- break;
- }
-
- if (!warning_displayed) {
- printf("Could not connect to wpa_supplicant: "
- "%s - re-trying\n", ctrl_ifname);
- warning_displayed = 1;
- }
- os_sleep(1, 0);
- continue;
- }
+ wpa_cli_interactive();
} else {
if (!global &&
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
@@ -4163,17 +3492,16 @@ int main(int argc, char *argv[])
return -1;
}
}
- }
- if (daemonize && os_daemonize(pid_file))
- return -1;
+ if (daemonize && os_daemonize(pid_file))
+ return -1;
- if (interactive)
- wpa_cli_interactive();
- else if (action_file)
- wpa_cli_action(ctrl_conn);
- else
- ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+ if (action_file)
+ wpa_cli_action(ctrl_conn);
+ else
+ ret = wpa_request(ctrl_conn, argc - optind,
+ &argv[optind]);
+ }
os_free(ctrl_ifname);
eloop_destroy();
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index a9ec2361..9b568f0f 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -52,7 +52,7 @@ int main(int argc, char *argv[])
return 1;
}
- pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32);
+ pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
printf("network={\n");
printf("\tssid=\"%s\"\n", ssid);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 47abd9aa..284a91d9 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -21,6 +21,7 @@
#include "rsn_supp/wpa.h"
#include "eloop.h"
#include "config.h"
+#include "utils/ext_password.h"
#include "l2_packet/l2_packet.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -40,6 +41,7 @@
#include "gas_query.h"
#include "ap.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bgscan.h"
#include "autoscan.h"
@@ -153,6 +155,11 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
keylen = 16;
alg = WPA_ALG_CCMP;
break;
+ case WPA_CIPHER_GCMP:
+ os_memcpy(key, ssid->psk, 16);
+ keylen = 16;
+ alg = WPA_ALG_GCMP;
+ break;
case WPA_CIPHER_TKIP:
/* WPA-None uses the same Michael MIC key for both TX and RX */
os_memcpy(key, ssid->psk, 16 + 8);
@@ -191,6 +198,17 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
* So, wait a second until scanning again.
*/
wpa_supplicant_req_scan(wpa_s, 1, 0);
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after timed out authentication");
+ }
+ }
+#endif /* CONFIG_P2P */
}
@@ -453,6 +471,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->bssid_filter = NULL;
wnm_bss_keep_alive_deinit(wpa_s);
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+
+ wpabuf_free(wpa_s->last_gas_resp);
}
@@ -554,8 +577,16 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
* optimization, so the initial connection is not
* affected.
*/
- } else
+ } else {
+ struct wpa_scan_results *scan_res;
wpa_s->bgscan_ssid = wpa_s->current_ssid;
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
+ 0);
+ if (scan_res) {
+ bgscan_notify_scan(wpa_s, scan_res);
+ wpa_scan_results_free(scan_res);
+ }
+ }
} else
wpa_s->bgscan_ssid = NULL;
}
@@ -631,6 +662,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpa_s->new_connection = 0;
wpa_s->reassociated_connection = 1;
wpa_drv_set_operstate(wpa_s, 1);
@@ -823,6 +855,8 @@ enum wpa_cipher cipher_suite2driver(int cipher)
return CIPHER_WEP104;
case WPA_CIPHER_CCMP:
return CIPHER_CCMP;
+ case WPA_CIPHER_GCMP:
+ return CIPHER_GCMP;
case WPA_CIPHER_TKIP:
default:
return CIPHER_TKIP;
@@ -999,6 +1033,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (sel & WPA_CIPHER_CCMP) {
wpa_s->group_cipher = WPA_CIPHER_CCMP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
+ } else if (sel & WPA_CIPHER_GCMP) {
+ wpa_s->group_cipher = WPA_CIPHER_GCMP;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
} else if (sel & WPA_CIPHER_TKIP) {
wpa_s->group_cipher = WPA_CIPHER_TKIP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
@@ -1018,6 +1055,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (sel & WPA_CIPHER_CCMP) {
wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
+ } else if (sel & WPA_CIPHER_GCMP) {
+ wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
} else if (sel & WPA_CIPHER_TKIP) {
wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
@@ -1099,13 +1139,70 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase) {
u8 psk[PMK_LEN];
- pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
- bss->ssid_len, 4096, psk, PMK_LEN);
+ pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
}
#endif /* CONFIG_NO_PBKDF2 */
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+ ssid->ext_psk);
+ char pw_str[64 + 1];
+ u8 psk[PMK_LEN];
+
+ if (pw == NULL) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
+ "found from external storage");
+ return -1;
+ }
+
+ if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
+ "PSK length %d in external storage",
+ (int) wpabuf_len(pw));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+ pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+ if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+ {
+ pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN);
+ os_memset(pw_str, 0, sizeof(pw_str));
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
+ "external passphrase)",
+ psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ } else
+#endif /* CONFIG_NO_PBKDF2 */
+ if (wpabuf_len(pw) == 2 * PMK_LEN) {
+ if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
+ "Invalid PSK hex string");
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
+ "PSK available");
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ }
+#endif /* CONFIG_EXT_PASSWORD */
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -1257,6 +1354,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"key management and encryption suites");
return;
}
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+ /*
+ * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+ * use non-WPA since the scan results did not indicate that the
+ * AP is using WPA or WPA2.
+ */
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_ie_len = 0;
+ wpa_s->wpa_proto = 0;
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -1570,10 +1677,8 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
struct wpa_ssid *old_ssid;
wpa_clear_keys(wpa_s, addr);
- wpa_supplicant_mark_disassoc(wpa_s);
old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = NULL;
- wpa_s->current_bss = NULL;
+ wpa_supplicant_mark_disassoc(wpa_s);
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
if (old_ssid != wpa_s->current_ssid)
@@ -1662,6 +1767,8 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
was_disabled = other_ssid->disabled;
other_ssid->disabled = 0;
+ if (was_disabled)
+ wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(
@@ -1682,6 +1789,7 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
was_disabled = ssid->disabled;
ssid->disabled = 0;
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
if (was_disabled != ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, ssid);
@@ -1752,6 +1860,9 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
disconnected = 1;
}
+ if (ssid)
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
/*
* Mark all other networks disabled or mark all networks enabled if no
* network specified.
@@ -1763,6 +1874,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
continue; /* do not change persistent P2P group data */
other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+ if (was_disabled && !other_ssid->disabled)
+ wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
@@ -2529,6 +2642,38 @@ static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
}
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+ char *val, *pos;
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+ eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+ if (!wpa_s->conf->ext_password_backend)
+ return 0;
+
+ val = os_strdup(wpa_s->conf->ext_password_backend);
+ if (val == NULL)
+ return -1;
+ pos = os_strchr(val, ':');
+ if (pos)
+ *pos++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+ wpa_s->ext_pw = ext_password_init(val, pos);
+ os_free(val);
+ if (wpa_s->ext_pw == NULL) {
+ wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+ return -1;
+ }
+ eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+ return 0;
+}
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
@@ -2754,6 +2899,9 @@ next_driver:
if (pcsc_reader_init(wpa_s) < 0)
return -1;
+ if (wpas_init_ext_pw(wpa_s) < 0)
+ return -1;
+
return 0;
}
@@ -3072,6 +3220,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
return NULL;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wifi_display_init(global) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return global;
}
@@ -3123,6 +3279,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
if (global == NULL)
return;
+#ifdef CONFIG_WIFI_DISPLAY
+ wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_P2P
wpas_p2p_deinit_global(global);
#endif /* CONFIG_P2P */
@@ -3182,6 +3341,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
}
}
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+ wpas_init_ext_pw(wpa_s);
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -3304,6 +3466,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
*/
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after failed association");
+ }
+ }
+#endif /* CONFIG_P2P */
}
@@ -3417,6 +3590,10 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
return 1; /* invalid WEP key */
}
+ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+ !ssid->ext_psk)
+ return 1;
+
return 0;
}
@@ -3429,3 +3606,63 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
return 0;
return -1;
}
+
+
+void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int dur;
+ struct os_time now;
+
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "Authentication failure but no known "
+ "SSID block");
+ return;
+ }
+
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ return;
+
+ ssid->auth_failures++;
+ if (ssid->auth_failures > 50)
+ dur = 300;
+ else if (ssid->auth_failures > 20)
+ dur = 120;
+ else if (ssid->auth_failures > 10)
+ dur = 60;
+ else if (ssid->auth_failures > 5)
+ dur = 30;
+ else if (ssid->auth_failures > 1)
+ dur = 20;
+ else
+ dur = 10;
+
+ os_get_time(&now);
+ if (now.sec + dur <= ssid->disabled_until.sec)
+ return;
+
+ ssid->disabled_until.sec = now.sec + dur;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
+ "id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+ ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->auth_failures, dur);
+}
+
+
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int clear_failures)
+{
+ if (ssid == NULL)
+ return;
+
+ if (ssid->disabled_until.sec) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
+ "id=%d ssid=\"%s\"",
+ ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ }
+ ssid->disabled_until.sec = 0;
+ ssid->disabled_until.usec = 0;
+ if (clear_failures)
+ ssid->auth_failures = 0;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3ebbcc26..2c07fd0a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -241,20 +241,30 @@ fast_reauth=1
# This is an optional set of parameters for automatic scanning
# within an interface in following format:
#autoscan=<autoscan module name>:<module parameters>
-# autoscan is like bgscan but on disconnected or inactive state.
-# For instance, on exponential module parameters would be <base>:<limit>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
#autoscan=exponential:3:300
# Which means a delay between scans on a base exponential of 3,
-# up to the limit of 300 seconds (3, 9, 27 ... 300)
-# For periodic module, parameters would be <fixed interval>
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
#autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
# 1 = only include configured SSIDs in scan results/BSS table
#filter_ssids=0
+# Password (and passphrase, etc.) backend for external storage
+# format: <backend name>[:<optional backend parameters>]
+#ext_password_backend=test:pw1=password|pw2=testing
+
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in P2P GO mode to clean up
+# inactive stations.
+#p2p_go_max_inactivity=300
+
# Interworking (IEEE 802.11u)
@@ -267,6 +277,14 @@ fast_reauth=1
# is enabled.
# hessid=00:11:22:33:44:55
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
+
# credential block
#
# Each credential used for automatic network selection is configured as a set
@@ -336,6 +354,26 @@ fast_reauth=1
# This is used to compare against the Domain Name List to figure out
# whether the AP is operated by the Home SP.
#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
# for example:
#
#cred={
@@ -350,6 +388,17 @@ fast_reauth=1
# imsi="310026-000000000"
# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
# Hotspot 2.0
# hs20=1
@@ -371,8 +420,10 @@ fast_reauth=1
# to external action script through wpa_cli as WPA_ID_STR environment
# variable to make it easier to do network specific configuration.
#
-# ssid: SSID (mandatory); either as an ASCII string with double quotation or
-# as hex string; network name
+# ssid: SSID (mandatory); network name in one of the optional formats:
+# - an ASCII string with double quotation
+# - a hex string (two characters per octet of SSID)
+# - a printf-escaped ASCII string P"<escaped string>"
#
# scan_ssid:
# 0 = do not scan this SSID with specific Probe Request frames (default)
@@ -473,7 +524,8 @@ fast_reauth=1
# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
# generated using the passphrase and SSID). ASCII passphrase must be between
-# 8 and 63 characters (inclusive).
+# 8 and 63 characters (inclusive). ext:<name of external PSK field> format can
+# be used to indicate that the PSK/passphrase is stored in external storage.
# This field is not needed, if WPA-EAP is used.
# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
@@ -542,7 +594,8 @@ fast_reauth=1
# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
# EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
# PSK) is also configured using this field. For EAP-GPSK, this is a
-# variable length PSK.
+# variable length PSK. ext:<name of external password field> format can
+# be used to indicate that the password is stored in external storage.
# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
# or more trusted CA certificates. If ca_cert and ca_path are not
# included, server certificate will not be verified. This is insecure and
@@ -645,6 +698,25 @@ fast_reauth=1
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+#
+# TLS-based methods can use the following parameters to control TLS behavior
+# (these are normally in the phase1 parameter, but can be used also in the
+# phase2 parameter when EAP-TLS is used within the inner tunnel):
+# tls_allow_md5=1 - allow MD5-based certificate signatures (depending on the
+# TLS library, these may be disabled by default to enforce stronger
+# security)
+# tls_disable_time_checks=1 - ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# tls_disable_session_ticket=1 - disable TLS Session Ticket extension
+# tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used
+# Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS
+# as a workaround for broken authentication server implementations unless
+# EAP workarounds are disabled with eap_workarounds=0.
+# For EAP-FAST, this must be set to 0 (or left unconfigured for the
+# default value to be used automatically).
+#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
# ca_cert2: File path to CA certificate file. This file can have one or more
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3f6669dc..523b50df 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -239,6 +239,12 @@ struct wpa_global {
WPA_CONC_PREF_STA,
WPA_CONC_PREF_P2P
} conc_pref;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ int wifi_display;
+#define MAX_WFD_SUBELEMS 10
+ struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
+#endif /* CONFIG_WIFI_DISPLAY */
};
@@ -249,6 +255,17 @@ enum offchannel_send_action_result {
OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
};
+struct wps_ap_info {
+ u8 bssid[ETH_ALEN];
+ enum wps_ap_info_type {
+ WPS_AP_NOT_SEL_REG,
+ WPS_AP_SEL_REG,
+ WPS_AP_SEL_REG_OUR
+ } type;
+ unsigned int tries;
+ struct os_time last_attempt;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -514,23 +531,14 @@ struct wpa_supplicant {
*/
char cross_connect_uplink[100];
- enum {
- P2P_GROUP_REMOVAL_UNKNOWN,
- P2P_GROUP_REMOVAL_REQUESTED,
- P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
- P2P_GROUP_REMOVAL_UNAVAILABLE,
- P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
-#ifdef ANDROID_P2P
- P2P_GROUP_REMOVAL_FREQ_CONFLICT
-#endif
- } removal_reason;
-
unsigned int p2p_cb_on_scan_complete:1;
+ unsigned int sta_scan_pending:1;
unsigned int p2p_auto_join:1;
unsigned int p2p_auto_pd:1;
unsigned int p2p_persistent_group:1;
unsigned int p2p_fallback_to_go_neg:1;
unsigned int p2p_pd_before_go_neg:1;
+ unsigned int p2p_go_ht40:1;
int p2p_persistent_id;
int p2p_go_intent;
int p2p_connect_freq;
@@ -547,6 +555,10 @@ struct wpa_supplicant {
struct wpa_ssid *connect_without_scan;
+ struct wps_ap_info *wps_ap;
+ size_t num_wps_ap;
+ int wps_ap_iter;
+
int after_wps;
int known_wps_freq;
unsigned int wps_freq;
@@ -564,6 +576,7 @@ struct wpa_supplicant {
unsigned int fetch_anqp_in_progress:1;
unsigned int network_select:1;
unsigned int auto_select:1;
+ unsigned int auto_network_select:1;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -577,6 +590,12 @@ struct wpa_supplicant {
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
+
+ struct ext_password_data *ext_pw;
+
+ struct wpabuf *last_gas_resp;
+ u8 last_gas_addr[ETH_ALEN];
+ u8 last_gas_dialog_token;
};
@@ -659,6 +678,9 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s);
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int clear_failures);
void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
/**
@@ -700,4 +722,6 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid)
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 0873b1a8..23966b86 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -43,6 +43,15 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
+static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
+{
+ os_free(wpa_s->wps_ap);
+ wpa_s->wps_ap = NULL;
+ wpa_s->num_wps_ap = 0;
+ wpa_s->wps_ap_iter = 0;
+}
+
+
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
if (!wpa_s->wps_success &&
@@ -66,6 +75,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
return 1;
}
+ wpas_wps_clear_ap_info(wpa_s);
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
@@ -263,9 +273,13 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid->eap.phase1 = NULL;
os_free(ssid->eap.eap_methods);
ssid->eap.eap_methods = NULL;
- if (!ssid->p2p_group)
+ if (!ssid->p2p_group) {
ssid->temporary = 0;
- ssid->bssid_set = 0;
+ ssid->bssid_set = 0;
+ }
+ ssid->disabled_until.sec = 0;
+ ssid->disabled_until.usec = 0;
+ ssid->auth_failures = 0;
} else {
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
"received credential");
@@ -353,16 +367,6 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_WPA;
break;
- case WPS_AUTH_WPA:
- ssid->auth_alg = WPA_AUTH_ALG_OPEN;
- ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- ssid->proto = WPA_PROTO_WPA;
- break;
- case WPS_AUTH_WPA2:
- ssid->auth_alg = WPA_AUTH_ALG_OPEN;
- ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- ssid->proto = WPA_PROTO_RSN;
- break;
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -712,6 +716,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
wpa_config_remove_network(wpa_s->conf, id);
}
}
+
+ wpas_wps_clear_ap_info(wpa_s);
}
@@ -907,6 +913,7 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
+ wpa_s->wps_ap_iter = 1;
wpas_wps_reassoc(wpa_s, ssid, bssid);
return rpin;
}
@@ -933,7 +940,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpas_clear_wps(wpa_s);
- }
+ } else
+ wpas_wps_clear_ap_info(wpa_s);
return 0;
}
@@ -1239,6 +1247,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ wpas_wps_clear_ap_info(wpa_s);
if (wpa_s->wps == NULL)
return;
@@ -1920,3 +1929,130 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_WPS_NFC */
+
+
+extern int wpa_debug_level;
+
+static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+ struct os_time now;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ if (wpa_s->wps_ap == NULL)
+ return;
+
+ os_get_time(&now);
+
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+
+ wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
+ "tries=%d last_attempt=%d sec ago blacklist=%d",
+ (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
+ ap->last_attempt.sec > 0 ?
+ (int) now.sec - (int) ap->last_attempt.sec : -1,
+ e ? e->count : 0);
+ }
+}
+
+
+static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->wps_ap == NULL)
+ return NULL;
+
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0)
+ return ap;
+ }
+
+ return NULL;
+}
+
+
+static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ struct wpabuf *wps;
+ enum wps_ap_info_type type;
+ struct wps_ap_info *ap;
+ int r;
+
+ if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
+ return;
+
+ wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+ if (wps == NULL)
+ return;
+
+ r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
+ if (r == 2)
+ type = WPS_AP_SEL_REG_OUR;
+ else if (r == 1)
+ type = WPS_AP_SEL_REG;
+ else
+ type = WPS_AP_NOT_SEL_REG;
+
+ wpabuf_free(wps);
+
+ ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
+ if (ap) {
+ if (ap->type != type) {
+ wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
+ " changed type %d -> %d",
+ MAC2STR(res->bssid), ap->type, type);
+ ap->type = type;
+ if (type != WPS_AP_NOT_SEL_REG)
+ wpa_blacklist_del(wpa_s, ap->bssid);
+ }
+ return;
+ }
+
+ ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
+ sizeof(struct wps_ap_info));
+ if (ap == NULL)
+ return;
+
+ wpa_s->wps_ap = ap;
+ ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
+ wpa_s->num_wps_ap++;
+
+ os_memset(ap, 0, sizeof(*ap));
+ os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
+ ap->type = type;
+ wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
+ MAC2STR(ap->bssid), ap->type);
+}
+
+
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ size_t i;
+
+ for (i = 0; i < scan_res->num; i++)
+ wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
+
+ wpas_wps_dump_ap_info(wpa_s);
+}
+
+
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wps_ap_info *ap;
+ if (!wpa_s->wps_ap_iter)
+ return;
+ ap = wpas_wps_get_ap_info(wpa_s, bssid);
+ if (ap == NULL)
+ return;
+ ap->tries++;
+ os_get_time(&ap->last_attempt);
+}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 5a49a8f2..36f1e021 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -10,6 +10,7 @@
#define WPS_SUPPLICANT_H
struct wpa_scan_res;
+struct wpa_scan_results;
#ifdef CONFIG_WPS
@@ -68,6 +69,9 @@ struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
const struct wpabuf *data);
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
#else /* CONFIG_WPS */
@@ -120,6 +124,16 @@ static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
return 0;
}
+static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+}
+
+static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_SUPPLICANT_H */